@onramper/onramper-react-native 1.2.2 → 1.3.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.
Files changed (96) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/README.md +46 -4
  3. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  4. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftinterface +107 -4
  5. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK +0 -0
  6. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  7. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +3560 -2684
  8. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  9. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +107 -4
  10. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  11. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +107 -4
  12. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK +0 -0
  13. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  14. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +3560 -2684
  15. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/OnramperSDK.yml +3523 -2651
  16. package/ios/HybridOnramperCheckoutButton.swift +77 -3
  17. package/ios/HybridOnramperNitro.swift +140 -78
  18. package/ios/OnramperSDKBridge.swift +19 -2
  19. package/ios/PreparedIntentRegistry.swift +124 -6
  20. package/ios/SDKLogRelay.swift +41 -0
  21. package/lib/commonjs/CheckoutButton.js +34 -0
  22. package/lib/commonjs/CheckoutButton.js.map +1 -0
  23. package/lib/commonjs/OnramperClient.js +69 -12
  24. package/lib/commonjs/OnramperClient.js.map +1 -1
  25. package/lib/commonjs/errors.js +19 -5
  26. package/lib/commonjs/errors.js.map +1 -1
  27. package/lib/commonjs/generated/OnramperCheckoutButtonConfig.json +1 -0
  28. package/lib/module/CheckoutButton.js +30 -0
  29. package/lib/module/CheckoutButton.js.map +1 -0
  30. package/lib/module/OnramperClient.js +69 -12
  31. package/lib/module/OnramperClient.js.map +1 -1
  32. package/lib/module/errors.js +19 -5
  33. package/lib/module/errors.js.map +1 -1
  34. package/lib/module/generated/OnramperCheckoutButtonConfig.json +1 -0
  35. package/lib/typescript/commonjs/src/CheckoutButton.d.ts +20 -0
  36. package/lib/typescript/commonjs/src/CheckoutButton.d.ts.map +1 -0
  37. package/lib/typescript/commonjs/src/OnramperClient.d.ts +5 -1
  38. package/lib/typescript/commonjs/src/OnramperClient.d.ts.map +1 -1
  39. package/lib/typescript/commonjs/src/errors.d.ts +6 -1
  40. package/lib/typescript/commonjs/src/errors.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/src/events.d.ts +10 -0
  42. package/lib/typescript/commonjs/src/events.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/src/index.d.ts +1 -1
  44. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts +6 -0
  46. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts +3 -0
  48. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/src/types.d.ts +32 -3
  50. package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
  51. package/lib/typescript/module/src/CheckoutButton.d.ts +20 -0
  52. package/lib/typescript/module/src/CheckoutButton.d.ts.map +1 -0
  53. package/lib/typescript/module/src/OnramperClient.d.ts +5 -1
  54. package/lib/typescript/module/src/OnramperClient.d.ts.map +1 -1
  55. package/lib/typescript/module/src/errors.d.ts +6 -1
  56. package/lib/typescript/module/src/errors.d.ts.map +1 -1
  57. package/lib/typescript/module/src/events.d.ts +10 -0
  58. package/lib/typescript/module/src/events.d.ts.map +1 -1
  59. package/lib/typescript/module/src/index.d.ts +1 -1
  60. package/lib/typescript/module/src/index.d.ts.map +1 -1
  61. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts +6 -0
  62. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -1
  63. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts +3 -0
  64. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts.map +1 -1
  65. package/lib/typescript/module/src/types.d.ts +32 -3
  66. package/lib/typescript/module/src/types.d.ts.map +1 -1
  67. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.cpp +11 -3
  68. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.hpp +44 -7
  69. package/nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.hpp +9 -0
  70. package/nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.hpp +6 -0
  71. package/nitrogen/generated/ios/c++/views/HybridOnramperCheckoutButtonComponent.mm +5 -0
  72. package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
  73. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +5 -5
  74. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec.swift +1 -0
  75. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec_cxx.swift +32 -0
  76. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec.swift +1 -0
  77. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec_cxx.swift +27 -11
  78. package/nitrogen/generated/ios/swift/OnramperNitroConfig.swift +16 -6
  79. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.cpp +2 -0
  80. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.hpp +4 -0
  81. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.cpp +1 -0
  82. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.hpp +1 -0
  83. package/nitrogen/generated/shared/c++/OnramperNitroConfig.hpp +10 -2
  84. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.cpp +11 -0
  85. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.hpp +3 -2
  86. package/nitrogen/generated/shared/json/OnramperCheckoutButtonConfig.json +1 -0
  87. package/package.json +5 -2
  88. package/src/CheckoutButton.ts +28 -0
  89. package/src/OnramperClient.ts +69 -9
  90. package/src/errors.ts +29 -6
  91. package/src/events.ts +5 -0
  92. package/src/generated/OnramperCheckoutButtonConfig.json +1 -0
  93. package/src/index.ts +3 -0
  94. package/src/specs/OnramperCheckoutButton.nitro.ts +6 -0
  95. package/src/specs/OnramperNitro.nitro.ts +3 -0
  96. package/src/types.ts +36 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,220 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [1.3.0]
6
+
7
+ Bundles the published, checksum-verified `OnramperSDK@1.3.0` for iOS.
8
+
9
+ Most checkout changes in this release come from
10
+ [OnramperSDK for iOS 1.3.0](https://github.com/onramper/onramper-ios/releases/tag/v1.3.0):
11
+ MoonPay Apple Pay, pending payments, customer-facing errors, structured logging, and
12
+ credential isolation. The React Native wrapper exposes these native capabilities in
13
+ JavaScript and adds prepared-checkout cleanup and client-lifecycle fixes. The demo adds
14
+ log-file management and checkout recovery.
15
+
16
+ ### Before you upgrade
17
+
18
+ - **Handle the new error, state and event cases.** Update exhaustive switches for the
19
+ additions below. Keep `paymentPending` separate from completion and failure; an
20
+ accepted payment may still be settling.
21
+ - **Previously signed-in users will sign in to OnramperID again.** The native SDK now
22
+ stores credentials separately by environment and removes the old shared entries once.
23
+ SDK session setup remains automatic; the next checkout requiring login presents
24
+ sign-in again.
25
+ - **Rebuild the native app.** After updating the package, run `pod install` in your iOS
26
+ project and rebuild. A JavaScript-only update cannot replace the bundled iOS SDK.
27
+
28
+ Existing checkout, prefill, button-rendering and session-refresh signatures are
29
+ unchanged. Minimum React Native and iOS versions are unchanged.
30
+
31
+ ### Included from iOS SDK 1.3.0
32
+
33
+ **MoonPay Apple Pay checkout.** When MoonPay is selected for an available Apple Pay
34
+ quote, the native checkout button handles MoonPay's Frames flow: guest checkout or
35
+ account onboarding, required payment disclosures, Apple Pay, and 3-D Secure verification
36
+ when needed. Integrators continue rendering the returned `button`; no separate MoonPay
37
+ WebView is required. The MoonPay sheet opens at a compact height and expands when the
38
+ provider needs more room. Required disclosures appear next to the Apple Pay button and
39
+ cannot be hidden. Coinbase and Paybis continue through the same API.
40
+
41
+ **Pending-payment outcome and UI.** The native SDK distinguishes an accepted payment
42
+ awaiting settlement from a completed payment. Its sheet shows **Payment processing**
43
+ with the transaction ID; dismissing the sheet preserves the pending outcome.
44
+
45
+ **Customer-facing errors and failure UI.** The native SDK supplies `userMessage` and
46
+ `supportCode`, and distinguishes confirmed payment failure from a checkout-surface error
47
+ with an unknown payment outcome. Its failure screen displays that copy and support
48
+ code. **Try Again** closes the sheet and starts a fresh checkout. The RN API below
49
+ exposes the same error categories and messages for the integrator's own UI.
50
+
51
+ **Structured, sanitized logging.** The native SDK produces structured records and
52
+ supports a custom log sink. HTTP paths use route templates, URLs are reduced to hosts,
53
+ and sensitive-looking values are redacted. Native `errorDescription` and `debugInfo`
54
+ also exclude URLs, response bodies, and tokens. Provider messages receive best-effort
55
+ redaction, so exported logs may still contain personal data. Logging remains off by
56
+ default; the RN wrapper forwards these native records to JavaScript.
57
+
58
+ **Environment-specific credentials.** The native SDK now keeps credentials separate
59
+ for development and production, preventing a session from carrying across environments.
60
+ The one-time sign-in requirement is described above.
61
+
62
+ ### React Native API additions
63
+
64
+ The following APIs expose the bundled native SDK's states, events, errors, logging, and
65
+ provider metadata to JavaScript.
66
+
67
+ **Pending-payment handling.** `OnramperState.kind` and `CheckoutEvent.type` now include
68
+ `paymentPending`. It means payment was accepted but settlement is pending, and does not
69
+ emit `completed`. Show a processing state and retain `currentTransactionId` to track the
70
+ transaction through your backend and webhooks. Do not start another payment just because
71
+ the first is pending.
72
+
73
+ ```ts
74
+ client.addEventListener('paymentPending', () => {
75
+ showProcessing(client.currentTransactionId);
76
+ });
77
+ ```
78
+
79
+ **Customer-facing errors and support codes.** The JavaScript `OnramperError` now exposes
80
+ the native SDK's `userMessage` for customer copy and `supportCode` for diagnostics.
81
+ Existing `code`, `message` and `info` fields remain available. These fields are preserved
82
+ across both failed events and rejected native SDK calls.
83
+
84
+ ```ts
85
+ client.addEventListener('failed', ({ error }) => {
86
+ const failure = OnramperError.from(error);
87
+ showError(failure.userMessage, failure.supportCode);
88
+ });
89
+
90
+ try {
91
+ await client.getCheckoutRequirements(request);
92
+ } catch (error) {
93
+ const failure = OnramperError.from(error);
94
+ showError(failure.userMessage, failure.supportCode);
95
+ }
96
+ ```
97
+
98
+ New JavaScript error codes mirroring iOS SDK 1.3.0:
99
+
100
+ - `paymentFailed`: the provider confirmed the payment failed.
101
+ - `providerFailed`: the checkout surface failed without confirming the payment outcome.
102
+ This does not prove that no payment was taken; follow `userMessage` and check
103
+ transaction status before offering another payment attempt.
104
+ - `applePayNotConfigured`: Apple Pay needs to be set up on the device.
105
+
106
+ `OnramperError.from()` supplies fallback customer copy and a support code for older or
107
+ manually constructed payloads. The new fields are optional on `OnramperErrorPayload` to
108
+ preserve compatibility with existing fixtures and callers.
109
+
110
+ **Structured SDK logs in JavaScript.** Configure `logLevel` and an optional `logHandler`
111
+ to receive native `OnramperLogRecord` values. Records contain a Unix-millisecond
112
+ timestamp, level, category, event, string-valued context and formatted message. The RN
113
+ bridge preserves native Console output while forwarding records to the callback.
114
+
115
+ ```ts
116
+ const client = new OnramperClient({
117
+ apiKey,
118
+ clientId,
119
+ environment: 'production',
120
+ onSessionExpired,
121
+ logLevel: 'info',
122
+ logHandler: record => diagnosticStore.append(record),
123
+ });
124
+ ```
125
+
126
+ Library logging defaults to `off`. Callbacks run in JavaScript, stop after `destroy()`,
127
+ and should do little work; callback exceptions do not interrupt checkout. Native
128
+ sanitization is preserved; choose appropriate retention and sharing controls for your
129
+ app's exported logs.
130
+
131
+ **Provider lifecycle events and metadata.** The wrapper exposes the native SDK's new
132
+ `challengeStarted`, `challengeCompleted` and `customerOnboardingRequired` events. These
133
+ describe progress, not payment completion. Optional `QuoteResponse.providerContext` preserves JSON values,
134
+ including executable flags and limits where supplied. `ProviderJSONValue` and
135
+ `PaymentDisclosure` are exported types, and finalized data types the optional
136
+ `providerBootstrap`. Provider metadata may contain tokens; avoid logging it or payment
137
+ URLs.
138
+
139
+ **Opt-in provider-event diagnostics.** The wrapper also exposes the native configuration
140
+ flags: `isEventLoggingEnabled` enables SDK event telemetry to the BFF.
141
+ `isEventConsoleLoggingEnabled` emits provider events at info level even when `logLevel`
142
+ is lower. Both default to `false`.
143
+
144
+ ### React Native wrapper fixes
145
+
146
+ - **Superseded quote preparations release abandoned buttons.** A newer preparation
147
+ invalidates older unmounted handles owned by that client, even if the newer request
148
+ fails. Superseded in-flight calls reject with `intentInvalidated`; ignore those when
149
+ waiting for the latest quote. Reset, sign-out and destruction clear owned handles, and
150
+ expired handles cannot mount. Other clients are unaffected. This cleans up local
151
+ views; it does not cancel a submitted payment or guarantee cancellation of a backend
152
+ request.
153
+ - **Client destruction is safe and explicit.** Repeated `destroy()` calls are harmless.
154
+ Subsequent operations reject, and listener subscriptions throw, with the typed
155
+ `clientDestroyed` error instead of Nitro's `NativeState is null`. Late results, events
156
+ and logs cannot update a destroyed JS client. Unmount the old button and create a new
157
+ client to start another session.
158
+ - **Native errors retain their context across Nitro.** Promise rejections preserve the
159
+ structured error code, customer message, support code and associated information,
160
+ matching failed-event payloads. Previously, exceptions could be reduced to a message
161
+ and classified as `unrecoverable`.
162
+
163
+ ### Demo app changes
164
+
165
+ - The bare RN demo offers **Get a new quote** after a failure before finalization,
166
+ replacing the disabled Buy button while preserving login. It fetches fresh
167
+ requirements without automatically retrying payment. Failures after finalization
168
+ retain the native outcome sheet.
169
+ - Pending payments appear separately from completion, and error displays use
170
+ customer-friendly messages and support codes.
171
+ - Settings now lists daily UTC log files with previews, sizes, individual sharing and
172
+ confirmed deletion. Demo recording is on by default and respects a saved off choice.
173
+ Files are excluded from backups, capped at 5 MiB in total and pruned after seven days
174
+ during use. The event panel remains an in-memory view.
175
+ - The Expo example demonstrates the new events, customer-facing errors and log callback.
176
+
177
+ ### Upgrading from stable 1.2.2
178
+
179
+ This stable release also includes the self-sizing checkout button and demo improvements
180
+ previously published in `1.2.2-1`. The native button reports its content height,
181
+ including its Terms of Service text. Style the button's container; `cloneElement(button,
182
+ { style })` does not style the native button.
183
+
184
+ Keep transaction webhooks configured for every provider and payment flow. In-app SDK
185
+ events complement backend transaction tracking.
186
+
187
+ ### Known issue in the Expo example
188
+
189
+ The Expo demo's native build on the tested Xcode 27 toolchain remains blocked by the
190
+ existing `ExpoModulesJSI` compiler error in `JavaScriptRuntime.swift:219`: “a C function
191
+ pointer can only be formed from a reference to a 'func' or a literal closure.” This was
192
+ reproduced before these changes. Expo JavaScript tests and type checking pass; the bare
193
+ RN app's Release build has been validated.
194
+
195
+ [iOS SDK 1.3.0 changelog](https://github.com/onramper/onramper-ios/blob/master/CHANGELOG.md#130)
196
+ · [React Native changes since 1.2.2-1](https://github.com/onramper/onramper-react-native/compare/v1.2.2-1...v1.3.0)
197
+
198
+ ## [1.2.2-1]
199
+
200
+ Wrapper-only change; still bundles `OnramperSDK@1.2.2`.
201
+
202
+ ### Fixed
203
+
204
+ - The native checkout button no longer draws over neighbouring views. It reports its content height
205
+ (for example when ToS text appears under the Buy button) and sizes itself to match, and clips any
206
+ overflow as a backstop.
207
+ - A checkout button given an intent that has expired or was already used now shows nothing, instead of
208
+ keeping the previous quote's button on screen.
209
+
210
+ ### Changed
211
+
212
+ - No public TypeScript type changes. Containers around `button` no longer need a `minHeight`.
213
+ - `button` is now an element of a small sizing wrapper rather than the native view itself, and it
214
+ manages its own `style`. Style passed with `cloneElement(button, { style })` is no longer applied;
215
+ style the containing `View` instead.
216
+ - The bare example app is now a demo app: environment switching, automatic SDK initialization,
217
+ currency / payment / country selection, and a settings sheet.
218
+
5
219
  ## [1.2.2]
6
220
 
7
221
  Bundles `OnramperSDK@1.2.2`.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Requires React Native 0.79+, `react-native-nitro-modules` 0.35+, the **New Archi
19
19
  { "expo": { "plugins": ["@onramper/onramper-react-native"] } }
20
20
  ```
21
21
 
22
- The plugin applies the required iOS build flag (it does not change your deployment target). Set your app's deployment target to **16.4+** — Expo SDK 56's own minimum (bare RN only needs 16.0). For bare-RN Podfile setup (Xcode 16+/26) and full details, see the [integration guide](docs/INTEGRATION.md).
22
+ The plugin applies the required iOS build flag (it does not change your deployment target). Set your app's deployment target to **16.4+** — Expo SDK 56's own minimum (bare RN only needs 16.0). For bare-RN Podfile setup (Xcode 16+/26) and full details, see the [integration guide](docs/GETTING_STARTED.md).
23
23
 
24
24
  ## Quick start
25
25
 
@@ -56,7 +56,7 @@ return (
56
56
  );
57
57
  ```
58
58
 
59
- The button renders natively and presents login + payment sheets internally. ToS is rendered inside the button view.
59
+ The button renders natively and presents login + payment sheets internally. ToS is rendered inside the button view, and the button sizes its own height to fit it — don't give its container a fixed height.
60
60
 
61
61
  Already know the user? Pass a third `prefill` argument (`email`, `firstName`, `lastName`, `phoneNumber` — all optional) to have the OnramperID screens arrive pre-populated. It's best-effort and never blocks sign-in. See [prefilling known user values](docs/GETTING_STARTED.md#prefilling-known-user-values) — note the caveat on `email` before supplying it.
62
62
 
@@ -65,6 +65,8 @@ Already know the user? Pass a third `prefill` argument (`email`, `firstName`, `l
65
65
  The SwiftUI `OnramperCheckoutButton` does not expose external callback hooks; checkout outcomes flow via the module-level event stream:
66
66
 
67
67
  ```ts
68
+ import { OnramperError } from '@onramper/onramper-react-native';
69
+
68
70
  const onFinalized = client.addEventListener('checkoutFinalized', ({ response }) => {
69
71
  // Durable transaction identifier: store this for support/reconciliation.
70
72
  persistTransactionId(response.onramperTransactionId);
@@ -75,7 +77,8 @@ const unsub = client.addEventListener('completed', (e) => {
75
77
  });
76
78
 
77
79
  const onFailed = client.addEventListener('failed', (e) => {
78
- console.log('failed:', e.error.code, e.error.message);
80
+ const failure = OnramperError.from(e.error);
81
+ showError(failure.userMessage, failure.supportCode);
79
82
  });
80
83
  ```
81
84
 
@@ -83,6 +86,12 @@ const onFailed = client.addEventListener('failed', (e) => {
83
86
  `onramperTransactionId` identifies the transaction and is available before payment rendering.
84
87
  `client.currentTransactionId` mirrors the same value; `reset()` clears it.
85
88
 
89
+ `paymentPending` means accepted but awaiting settlement. Show processing and track
90
+ `currentTransactionId`; do not treat it as completion or automatically restart payment.
91
+ The native button also handles MoonPay onboarding and 3-D Secure. Observe
92
+ `customerOnboardingRequired`, `challengeStarted`, and `challengeCompleted` for progress.
93
+ These events do not establish payment success. All flows still require backend webhooks.
94
+
86
95
  ## Error handling
87
96
 
88
97
  All native errors arrive as `OnramperError` with a typed `code`:
@@ -103,8 +112,41 @@ try {
103
112
  }
104
113
  ```
105
114
 
115
+ Use `error.userMessage` for customer copy and `error.supportCode` for support.
116
+ `paymentFailed` confirms payment failure; `providerFailed` does not confirm the
117
+ payment outcome. The same fields survive native Promise rejections and failed events.
106
118
  Full code list in `src/errors.ts`.
107
119
 
120
+ ## Client lifecycle
121
+
122
+ Each client keeps only its latest unmounted checkout button. A new
123
+ `getCheckoutRequirements()` call, `reset()`, or `signOut()` invalidates older
124
+ preparations; an in-flight request that becomes obsolete rejects with
125
+ `intentInvalidated`. When replacing a quote, remove the previous button and
126
+ ignore that obsolete request's rejection while waiting for the current request.
127
+ Do not treat it as a payment failure. Other clients are unaffected.
128
+
129
+ Call `destroy()` when disposing of a client and unmount its checkout button.
130
+ Repeated destruction is safe. Further operations reject with `clientDestroyed`;
131
+ new listener subscriptions throw the same typed error. Pending results and late
132
+ callbacks cannot update the destroyed JS client. Create a new `OnramperClient`
133
+ to start again; calling `initialize()` on a destroyed instance does not revive it.
134
+
135
+ These rules release local prepared views; they do not cancel an already submitted
136
+ payment or guarantee cancellation of a request already sent to the backend.
137
+
138
+ ## Diagnostic logs
139
+
140
+ Pass `logLevel: 'info'` (or `'debug'`) and `logHandler: record => yourStore.append(record)`
141
+ to receive structured `OnramperLogRecord`s in JavaScript. Native Console output is
142
+ preserved. Logging defaults to off; storage and export are owned by your app.
143
+ The bare demo records by default: Settings → Diagnostic logs lists daily files
144
+ with previews, individual sharing, and confirmed deletion.
145
+ See [debugging](docs/DEBUGGING.md) for the record shape and retention guidance.
146
+
147
+ For migration details, including new enum cases and one-time OnramperID sign-in,
148
+ see [1.3.0 release notes](CHANGELOG.md#130).
149
+
108
150
  ## Versioning
109
151
 
110
152
  `@onramper/onramper-react-native@X.Y.Z` always bundles `OnramperSDK@X.Y.Z` (iOS). Wrapper-only patches are published as `X.Y.Z-N` pre-releases (`npm install @onramper/onramper-react-native@next` to opt in).
@@ -120,6 +162,6 @@ The vendored `OnramperSDK.xcframework` already ships its own `PrivacyInfo.xcpriv
120
162
  ## Troubleshooting
121
163
 
122
164
  - **`pod install` fails finding the xcframework** — confirm `node_modules/@onramper/onramper-react-native/ios/Frameworks/OnramperSDK.xcframework/` exists.
123
- - **Bare RN build fails with `module map file ... not found` (Xcode 16+/26)** — disable explicit Swift modules in your `Podfile` `post_install` (`SWIFT_ENABLE_EXPLICIT_MODULES = NO`). Expo apps get this automatically via the config plugin. See the [integration guide](docs/INTEGRATION.md).
165
+ - **Bare RN build fails with `module map file ... not found` (Xcode 16+/26)** — disable explicit Swift modules in your `Podfile` `post_install` (`SWIFT_ENABLE_EXPLICIT_MODULES = NO`). Expo apps get this automatically via the config plugin. See the [integration guide](docs/GETTING_STARTED.md).
124
166
  - **App Attest errors in simulator** — expected. App Attest only works on real devices. The SDK surfaces this as `attestationFailed`.
125
167
  - **Buttons appear but sheets don't open** — the host RN screen must be inside a normal `UIViewController` (the default). Modal-presented screens may need extra care; report an issue with a repro.
@@ -9,12 +9,14 @@ import Foundation
9
9
  import Foundation/*.Bundle*/
10
10
  import Foundation/*.ProcessInfo*/
11
11
  import Foundation/*.URL*/
12
+ import PassKit
12
13
  import Security
13
14
  import Swift
14
15
  import SwiftUI
15
16
  import UIKit
16
17
  import WebKit
17
18
  import _Concurrency
19
+ import _PassKit_SwiftUI
18
20
  import _StringProcessing
19
21
  import _SwiftConcurrencyShims
20
22
  import _WebKit_SwiftUI
@@ -33,6 +35,24 @@ extension OnramperSDK.ToSRequirement {
33
35
  public func consentSentencePlainText(buttonLabel: Swift.String) -> Swift.String?
34
36
  #endif
35
37
  }
38
+ public struct OnramperLogRecord : Swift.Sendable, Swift.Equatable {
39
+ public let timestamp: Foundation.Date
40
+ public let level: OnramperSDK.LogLevel
41
+ public let category: Swift.String
42
+ public let event: Swift.String
43
+ public let context: [Swift.String : Swift.String]
44
+ public var message: Swift.String {
45
+ get
46
+ }
47
+ public init(timestamp: Foundation.Date = Date(), level: OnramperSDK.LogLevel, category: Swift.String, event: Swift.String, context: [Swift.String : Swift.String])
48
+ public static func == (a: OnramperSDK.OnramperLogRecord, b: OnramperSDK.OnramperLogRecord) -> Swift.Bool
49
+ }
50
+ public typealias OnramperLogHandler = @Sendable (OnramperSDK.OnramperLogRecord) -> Swift.Void
51
+ public enum OnramperLog {
52
+ public static let subsystem: Swift.String
53
+ public static let isVerboseBuild: Swift.Bool
54
+ public static let systemHandler: @Sendable (_ record: OnramperSDK.OnramperLogRecord) -> Swift.Void
55
+ }
36
56
  public enum LogLevel : Swift.Int, Swift.Sendable, Swift.Comparable {
37
57
  case off
38
58
  case error
@@ -47,6 +67,14 @@ public enum LogLevel : Swift.Int, Swift.Sendable, Swift.Comparable {
47
67
  get
48
68
  }
49
69
  }
70
+ extension OnramperSDK.OnramperError {
71
+ public var userMessage: Swift.String {
72
+ get
73
+ }
74
+ public var supportCode: Swift.String {
75
+ get
76
+ }
77
+ }
50
78
  public enum OnramperError : Foundation.LocalizedError, Swift.Equatable, Swift.Sendable {
51
79
  case notInitialized
52
80
  case initializationFailed(Swift.String)
@@ -56,6 +84,7 @@ public enum OnramperError : Foundation.LocalizedError, Swift.Equatable, Swift.Se
56
84
  case networkError(code: Swift.Int, message: Swift.String)
57
85
  case decodingError(Swift.String)
58
86
  case timeout
87
+ case paymentFailed(Swift.String)
59
88
  case requirementNotSatisfied(Swift.String)
60
89
  case amountOutOfRange(min: Swift.Double, max: Swift.Double)
61
90
  case oidcFlowCancelled
@@ -65,6 +94,7 @@ public enum OnramperError : Foundation.LocalizedError, Swift.Equatable, Swift.Se
65
94
  case userTokenRefreshFailed(Swift.String)
66
95
  case webviewLoadFailed(Swift.String)
67
96
  case deepLinkFailed(Swift.String)
97
+ case providerFailed(Swift.String)
68
98
  case invalidRequest(field: Swift.String?, debugInfo: Swift.String?)
69
99
  case quoteUnavailable(debugInfo: Swift.String?)
70
100
  case checkoutForbidden(debugInfo: Swift.String?)
@@ -74,6 +104,7 @@ public enum OnramperError : Foundation.LocalizedError, Swift.Equatable, Swift.Se
74
104
  case deviceBlocked
75
105
  case securityStorageFailed(status: Swift.Int32)
76
106
  case securityTrustFailed(host: Swift.String)
107
+ case applePayNotConfigured
77
108
  #if compiler(>=5.3) && $NonescapableTypes
78
109
  public var errorDescription: Swift.String? {
79
110
  get
@@ -95,8 +126,12 @@ public enum CheckoutEvent : Swift.Sendable {
95
126
  case providerReady
96
127
  case paymentAuthorized
97
128
  case paymentProcessing
129
+ case paymentPending
98
130
  case paymentCancelled
99
131
  case providerError(reason: Swift.String)
132
+ case challengeStarted
133
+ case challengeCompleted
134
+ case customerOnboardingRequired
100
135
  }
101
136
  @_Concurrency.MainActor public protocol OnramperDelegate : AnyObject {
102
137
  @_Concurrency.MainActor func onramperClient(_ client: OnramperSDK.OnramperClient, didChangeState state: OnramperSDK.OnramperState)
@@ -123,12 +158,20 @@ public struct CheckoutFinalizeRequest : Swift.Codable, Swift.Sendable {
123
158
  public let onramperTransactionData: OnramperSDK.OnramperTransactionData
124
159
  public var requirementCompletions: [OnramperSDK.RequirementCompletion]?
125
160
  public var partnerContext: Swift.String?
161
+ public var providerBootstrap: OnramperSDK.ProviderBootstrapRequest?
126
162
  #if compiler(>=5.3) && $NonescapableTypes
127
- public init(headlessCheckoutId: Swift.String, quote: OnramperSDK.QuoteResponse, encryption: OnramperSDK.EncryptedPayload, onramperTransactionData: OnramperSDK.OnramperTransactionData, requirementCompletions: [OnramperSDK.RequirementCompletion]? = nil, partnerContext: Swift.String? = nil)
163
+ public init(headlessCheckoutId: Swift.String, quote: OnramperSDK.QuoteResponse, encryption: OnramperSDK.EncryptedPayload, onramperTransactionData: OnramperSDK.OnramperTransactionData, requirementCompletions: [OnramperSDK.RequirementCompletion]? = nil, partnerContext: Swift.String? = nil, providerBootstrap: OnramperSDK.ProviderBootstrapRequest? = nil)
128
164
  #endif
129
165
  public func encode(to encoder: any Swift.Encoder) throws
130
166
  public init(from decoder: any Swift.Decoder) throws
131
167
  }
168
+ public struct ProviderBootstrapRequest : Swift.Codable, Swift.Sendable {
169
+ public let publicKey: Swift.String
170
+ public let channelId: Swift.String
171
+ public init(publicKey: Swift.String, channelId: Swift.String)
172
+ public func encode(to encoder: any Swift.Encoder) throws
173
+ public init(from decoder: any Swift.Decoder) throws
174
+ }
132
175
  public enum CompletionRequirementType : Swift.String, Swift.Codable, Swift.Sendable {
133
176
  case tos
134
177
  case privacyPolicy
@@ -171,7 +214,18 @@ public struct HeadlessCheckoutData : Swift.Codable, Swift.Sendable {
171
214
  public let checkoutPaymentType: OnramperSDK.CheckoutPaymentType
172
215
  public let url: Swift.String
173
216
  public let renderType: OnramperSDK.RenderType
174
- public init(checkoutPaymentType: OnramperSDK.CheckoutPaymentType, url: Swift.String, renderType: OnramperSDK.RenderType)
217
+ public let providerBootstrap: OnramperSDK.ProviderBootstrapResponse?
218
+ #if compiler(>=5.3) && $NonescapableTypes
219
+ public init(checkoutPaymentType: OnramperSDK.CheckoutPaymentType, url: Swift.String, renderType: OnramperSDK.RenderType, providerBootstrap: OnramperSDK.ProviderBootstrapResponse? = nil)
220
+ #endif
221
+ public func encode(to encoder: any Swift.Encoder) throws
222
+ public init(from decoder: any Swift.Decoder) throws
223
+ }
224
+ public struct ProviderBootstrapResponse : Swift.Codable, Swift.Sendable {
225
+ public let framesBaseUrl: Swift.String?
226
+ #if compiler(>=5.3) && $NonescapableTypes
227
+ public init(framesBaseUrl: Swift.String? = nil)
228
+ #endif
175
229
  public func encode(to encoder: any Swift.Encoder) throws
176
230
  public init(from decoder: any Swift.Decoder) throws
177
231
  }
@@ -365,6 +419,22 @@ public struct EncryptedPayload : Swift.Codable, Swift.Sendable, Swift.Equatable
365
419
  public func encode(to encoder: any Swift.Encoder) throws
366
420
  public init(from decoder: any Swift.Decoder) throws
367
421
  }
422
+ public struct QuoteQuery : Swift.Codable, Swift.Sendable {
423
+ public let headlessCheckoutId: Swift.String
424
+ public let onramperTransactionData: OnramperSDK.OnramperTransactionData
425
+ public let providerContext: OnramperSDK.QuoteProviderContext?
426
+ #if compiler(>=5.3) && $NonescapableTypes
427
+ public init(headlessCheckoutId: Swift.String, onramperTransactionData: OnramperSDK.OnramperTransactionData, providerContext: OnramperSDK.QuoteProviderContext? = nil)
428
+ #endif
429
+ public func encode(to encoder: any Swift.Encoder) throws
430
+ public init(from decoder: any Swift.Decoder) throws
431
+ }
432
+ public struct HeadlessQuoteResponse : Swift.Codable, Swift.Sendable {
433
+ public let quote: OnramperSDK.QuoteResponse
434
+ public init(quote: OnramperSDK.QuoteResponse)
435
+ public func encode(to encoder: any Swift.Encoder) throws
436
+ public init(from decoder: any Swift.Decoder) throws
437
+ }
368
438
  public struct OnramperUserPrefill : Swift.Sendable, Swift.Equatable {
369
439
  public var email: Swift.String?
370
440
  public var firstName: Swift.String?
@@ -384,13 +454,42 @@ public struct QuoteResponse : Swift.Codable, Swift.Sendable, Swift.Equatable {
384
454
  public let networkFee: Swift.Double
385
455
  public let transactionFee: Swift.Double
386
456
  public let recommendations: [Swift.String]?
457
+ public let providerContext: OnramperSDK.QuoteResponseProviderContext?
387
458
  #if compiler(>=5.3) && $NonescapableTypes
388
- public init(quoteId: Swift.String, ramp: Swift.String, rate: Swift.Double, payout: Swift.Double, paymentMethod: Swift.String, networkFee: Swift.Double, transactionFee: Swift.Double, recommendations: [Swift.String]? = nil)
459
+ public init(quoteId: Swift.String, ramp: Swift.String, rate: Swift.Double, payout: Swift.Double, paymentMethod: Swift.String, networkFee: Swift.Double, transactionFee: Swift.Double, recommendations: [Swift.String]? = nil, providerContext: OnramperSDK.QuoteResponseProviderContext? = nil)
389
460
  #endif
390
461
  public static func == (a: OnramperSDK.QuoteResponse, b: OnramperSDK.QuoteResponse) -> Swift.Bool
391
462
  public func encode(to encoder: any Swift.Encoder) throws
392
463
  public init(from decoder: any Swift.Decoder) throws
393
464
  }
465
+ public typealias QuoteProviderContext = [Swift.String : Swift.String]
466
+ public typealias QuoteResponseProviderContext = [Swift.String : OnramperSDK.ProviderJSONValue]
467
+ public enum ProviderJSONValue : Swift.Codable, Swift.Sendable, Swift.Equatable, Swift.ExpressibleByStringLiteral {
468
+ case string(Swift.String), number(Swift.Double), bool(Swift.Bool), null
469
+ case array([OnramperSDK.ProviderJSONValue]), object([Swift.String : OnramperSDK.ProviderJSONValue])
470
+ public init(stringLiteral value: Swift.String)
471
+ #if compiler(>=5.3) && $NonescapableTypes
472
+ public var stringValue: Swift.String? {
473
+ get
474
+ }
475
+ #endif
476
+ public init(from decoder: any Swift.Decoder) throws
477
+ public func encode(to encoder: any Swift.Encoder) throws
478
+ public static func == (a: OnramperSDK.ProviderJSONValue, b: OnramperSDK.ProviderJSONValue) -> Swift.Bool
479
+ public typealias ExtendedGraphemeClusterLiteralType = Swift.String
480
+ public typealias StringLiteralType = Swift.String
481
+ public typealias UnicodeScalarLiteralType = Swift.String
482
+ }
483
+ public struct PaymentDisclosure : Swift.Codable, Swift.Sendable, Swift.Equatable {
484
+ public let code: Swift.String
485
+ public let version: Swift.String
486
+ public let contentMarkdown: Swift.String
487
+ public let contentHtml: Swift.String
488
+ public init(code: Swift.String, version: Swift.String, contentMarkdown: Swift.String, contentHtml: Swift.String)
489
+ public static func == (a: OnramperSDK.PaymentDisclosure, b: OnramperSDK.PaymentDisclosure) -> Swift.Bool
490
+ public func encode(to encoder: any Swift.Encoder) throws
491
+ public init(from decoder: any Swift.Decoder) throws
492
+ }
394
493
  public enum TransactionType : Swift.String, Swift.Codable, Swift.Sendable {
395
494
  case buy
396
495
  case sell
@@ -490,6 +589,7 @@ public struct OnramperConfiguration : Swift.Sendable {
490
589
  public let environment: OnramperSDK.OnramperConfiguration.Environment
491
590
  public let theme: OnramperSDK.OnramperConfiguration.Theme
492
591
  public let logLevel: OnramperSDK.LogLevel
592
+ public let logHandler: OnramperSDK.OnramperLogHandler?
493
593
  public let isEventLoggingEnabled: Swift.Bool
494
594
  public let isEventConsoleLoggingEnabled: Swift.Bool
495
595
  public let sessionExpirationHandler: @Sendable () async throws -> OnramperSDK.SessionCredentials
@@ -517,7 +617,9 @@ public struct OnramperConfiguration : Swift.Sendable {
517
617
  get
518
618
  }
519
619
  }
520
- public init(apiKey: Swift.String, clientId: Swift.String, environment: OnramperSDK.OnramperConfiguration.Environment = .production, theme: OnramperSDK.OnramperConfiguration.Theme = .system, logLevel: OnramperSDK.LogLevel = .off, isEventLoggingEnabled: Swift.Bool = false, isEventConsoleLoggingEnabled: Swift.Bool = false, sessionExpirationHandler: @escaping @Sendable () async throws -> OnramperSDK.SessionCredentials)
620
+ #if compiler(>=5.3) && $NonescapableTypes
621
+ public init(apiKey: Swift.String, clientId: Swift.String, environment: OnramperSDK.OnramperConfiguration.Environment = .production, theme: OnramperSDK.OnramperConfiguration.Theme = .system, logLevel: OnramperSDK.LogLevel = .off, logHandler: OnramperSDK.OnramperLogHandler? = nil, isEventLoggingEnabled: Swift.Bool = false, isEventConsoleLoggingEnabled: Swift.Bool = false, sessionExpirationHandler: @escaping @Sendable () async throws -> OnramperSDK.SessionCredentials)
622
+ #endif
521
623
  }
522
624
  public enum OnramperState : Swift.Sendable {
523
625
  case idle
@@ -529,6 +631,7 @@ public enum OnramperState : Swift.Sendable {
529
631
  case readyToCheckout
530
632
  case finalizing
531
633
  case rendering(OnramperSDK.OnramperState.RenderContext)
634
+ case paymentPending
532
635
  case completed
533
636
  case failed(OnramperSDK.OnramperError)
534
637
  public struct RenderContext : Swift.Sendable {