@onramper/onramper-react-native 1.2.0 → 1.2.2-1

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 (77) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +10 -1
  3. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Info.plist +0 -0
  4. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  5. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftinterface +12 -1
  6. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK +0 -0
  7. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/Info.plist +0 -0
  8. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  9. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +2240 -2234
  10. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Info.plist +0 -0
  11. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  12. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +12 -1
  13. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  14. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +12 -1
  15. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK +0 -0
  16. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/Info.plist +0 -0
  17. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  18. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +2240 -2234
  19. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/OnramperSDK.yml +2206 -2200
  20. package/ios/HybridOnramperCheckoutButton.swift +77 -3
  21. package/ios/HybridOnramperNitro.swift +12 -0
  22. package/lib/commonjs/CheckoutButton.js +34 -0
  23. package/lib/commonjs/CheckoutButton.js.map +1 -0
  24. package/lib/commonjs/OnramperClient.js +38 -8
  25. package/lib/commonjs/OnramperClient.js.map +1 -1
  26. package/lib/commonjs/generated/OnramperCheckoutButtonConfig.json +1 -0
  27. package/lib/module/CheckoutButton.js +30 -0
  28. package/lib/module/CheckoutButton.js.map +1 -0
  29. package/lib/module/OnramperClient.js +38 -8
  30. package/lib/module/OnramperClient.js.map +1 -1
  31. package/lib/module/generated/OnramperCheckoutButtonConfig.json +1 -0
  32. package/lib/typescript/commonjs/src/CheckoutButton.d.ts +20 -0
  33. package/lib/typescript/commonjs/src/CheckoutButton.d.ts.map +1 -0
  34. package/lib/typescript/commonjs/src/OnramperClient.d.ts +5 -0
  35. package/lib/typescript/commonjs/src/OnramperClient.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts +6 -0
  37. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts +1 -0
  39. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts.map +1 -1
  40. package/lib/typescript/commonjs/src/types.d.ts +2 -0
  41. package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
  42. package/lib/typescript/module/src/CheckoutButton.d.ts +20 -0
  43. package/lib/typescript/module/src/CheckoutButton.d.ts.map +1 -0
  44. package/lib/typescript/module/src/OnramperClient.d.ts +5 -0
  45. package/lib/typescript/module/src/OnramperClient.d.ts.map +1 -1
  46. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts +6 -0
  47. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -1
  48. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts +1 -0
  49. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts.map +1 -1
  50. package/lib/typescript/module/src/types.d.ts +2 -0
  51. package/lib/typescript/module/src/types.d.ts.map +1 -1
  52. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.cpp +16 -0
  53. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.hpp +75 -0
  54. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Umbrella.hpp +1 -0
  55. package/nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.hpp +9 -0
  56. package/nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.hpp +7 -0
  57. package/nitrogen/generated/ios/c++/views/HybridOnramperCheckoutButtonComponent.mm +5 -0
  58. package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
  59. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +53 -0
  60. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec.swift +1 -0
  61. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec_cxx.swift +32 -0
  62. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec.swift +1 -0
  63. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec_cxx.swift +22 -0
  64. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.cpp +2 -0
  65. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.hpp +4 -0
  66. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.cpp +1 -0
  67. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.hpp +2 -0
  68. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.cpp +11 -0
  69. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.hpp +3 -2
  70. package/nitrogen/generated/shared/json/OnramperCheckoutButtonConfig.json +1 -0
  71. package/package.json +4 -2
  72. package/src/CheckoutButton.ts +28 -0
  73. package/src/OnramperClient.ts +40 -6
  74. package/src/generated/OnramperCheckoutButtonConfig.json +1 -0
  75. package/src/specs/OnramperCheckoutButton.nitro.ts +6 -0
  76. package/src/specs/OnramperNitro.nitro.ts +2 -0
  77. package/src/types.ts +2 -0
@@ -36,6 +36,16 @@ namespace margelo::nitro::onramper::views {
36
36
  throw std::runtime_error(std::string("OnramperCheckoutButton.intentHandle: ") + exc.what());
37
37
  }
38
38
  }()),
39
+ onContentHeightChange([&]() -> CachedProp<std::optional<std::function<void(double /* height */)>>> {
40
+ try {
41
+ const react::RawValue* rawValue = rawProps.at("onContentHeightChange", nullptr, nullptr);
42
+ if (rawValue == nullptr) return sourceProps.onContentHeightChange;
43
+ const auto& [runtime, value] = (std::pair<jsi::Runtime*, jsi::Value>)*rawValue;
44
+ return CachedProp<std::optional<std::function<void(double /* height */)>>>::fromRawValue(*runtime, value.asObject(*runtime).getProperty(*runtime, PropNameIDCache::get(*runtime, "f")), sourceProps.onContentHeightChange);
45
+ } catch (const std::exception& exc) {
46
+ throw std::runtime_error(std::string("OnramperCheckoutButton.onContentHeightChange: ") + exc.what());
47
+ }
48
+ }()),
39
49
  hybridRef([&]() -> CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridOnramperCheckoutButtonSpec>& /* ref */)>>> {
40
50
  try {
41
51
  const react::RawValue* rawValue = rawProps.at("hybridRef", nullptr, nullptr);
@@ -50,6 +60,7 @@ namespace margelo::nitro::onramper::views {
50
60
  bool HybridOnramperCheckoutButtonProps::filterObjectKeys(const std::string& propName) {
51
61
  switch (hashString(propName)) {
52
62
  case hashString("intentHandle"): return true;
63
+ case hashString("onContentHeightChange"): return true;
53
64
  case hashString("hybridRef"): return true;
54
65
  default: return false;
55
66
  }
@@ -17,10 +17,10 @@
17
17
  #include <react/renderer/components/view/ViewProps.h>
18
18
 
19
19
  #include <string>
20
- #include <memory>
21
- #include "HybridOnramperCheckoutButtonSpec.hpp"
22
20
  #include <functional>
23
21
  #include <optional>
22
+ #include <memory>
23
+ #include "HybridOnramperCheckoutButtonSpec.hpp"
24
24
 
25
25
  namespace margelo::nitro::onramper::views {
26
26
 
@@ -43,6 +43,7 @@ namespace margelo::nitro::onramper::views {
43
43
 
44
44
  public:
45
45
  CachedProp<std::string> intentHandle;
46
+ CachedProp<std::optional<std::function<void(double /* height */)>>> onContentHeightChange;
46
47
  CachedProp<std::optional<std::function<void(const std::shared_ptr<HybridOnramperCheckoutButtonSpec>& /* ref */)>>> hybridRef;
47
48
 
48
49
  private:
@@ -5,6 +5,7 @@
5
5
  "directEventTypes": {},
6
6
  "validAttributes": {
7
7
  "intentHandle": true,
8
+ "onContentHeightChange": true,
8
9
  "hybridRef": true
9
10
  }
10
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onramper/onramper-react-native",
3
- "version": "1.2.0",
3
+ "version": "1.2.2-1",
4
4
  "description": "React Native wrapper for the Onramper iOS SDK",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/module/index.js",
@@ -64,7 +64,7 @@
64
64
  "license": "Apache-2.0",
65
65
  "homepage": "https://github.com/onramper/onramper-react-native#readme",
66
66
  "onramperSDK": {
67
- "checksum": "2d0f28702120326e5ebb191cb2a812b11bf58a9672fcde8cf1762182e96e932b"
67
+ "checksum": "754184c10a736e1db3292b592ca634ddbaa61dd01540b60610df4aa73a61de9a"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "react": ">=19.0.0",
@@ -76,12 +76,14 @@
76
76
  "@expo/config-plugins": "^10.0.0",
77
77
  "@types/jest": "^29.5.14",
78
78
  "@types/react": "~19.2.0",
79
+ "@types/react-test-renderer": "^19.3.0",
79
80
  "jest": "^29.7.0",
80
81
  "nitrogen": "^0.35.9",
81
82
  "react": "19.2.3",
82
83
  "react-native": "0.85.3",
83
84
  "react-native-builder-bob": "^0.43.0",
84
85
  "react-native-nitro-modules": "^0.35.9",
86
+ "react-test-renderer": "^19.2.3",
85
87
  "ts-jest": "^29.4.10",
86
88
  "typescript": "~5.8.3"
87
89
  },
@@ -0,0 +1,28 @@
1
+ import { createElement, useMemo, useState } from 'react';
2
+ import { callback } from 'react-native-nitro-modules';
3
+
4
+ import { OnramperCheckoutButtonView } from './OnramperCheckoutButtonView';
5
+
6
+ // Height of the bare Buy button. Used until native reports the measured content
7
+ // height so the first frame isn't collapsed.
8
+ export const CHECKOUT_BUTTON_FALLBACK_HEIGHT = 56;
9
+
10
+ export interface CheckoutButtonProps {
11
+ intentHandle: string;
12
+ }
13
+
14
+ /**
15
+ * Sizes the native checkout button to its SwiftUI content. The content grows when
16
+ * the SDK shows ToS text under the Buy button (which can change after mount), and
17
+ * Yoga can't measure a SwiftUI view — so native reports the height and it is
18
+ * applied here as an explicit `height`.
19
+ */
20
+ export function CheckoutButton({ intentHandle }: CheckoutButtonProps) {
21
+ const [height, setHeight] = useState<number | null>(null);
22
+ const onContentHeightChange = useMemo(() => callback((h: number) => setHeight(Math.ceil(h))), []);
23
+ return createElement(OnramperCheckoutButtonView, {
24
+ intentHandle,
25
+ onContentHeightChange,
26
+ style: { width: '100%', height: height ?? CHECKOUT_BUTTON_FALLBACK_HEIGHT },
27
+ });
28
+ }
@@ -1,6 +1,6 @@
1
1
  import { type ReactElement, createElement } from 'react';
2
2
 
3
- import { OnramperCheckoutButtonView } from './OnramperCheckoutButtonView';
3
+ import { CheckoutButton } from './CheckoutButton';
4
4
  import { createOnramperNative } from './OnramperNative';
5
5
  import { OnramperError } from './errors';
6
6
  import type { CheckoutEvent, EventName, EventPayload } from './events';
@@ -30,12 +30,14 @@ export interface GetCheckoutRequirementsResult {
30
30
  export class OnramperClient {
31
31
  state: OnramperState = { kind: 'idle' };
32
32
  lastError: OnramperError | null = null;
33
+ currentTransactionId: string | null = null;
33
34
 
34
35
  // Each client owns its own native instance (and thus its own SDK client).
35
36
  private readonly native = createOnramperNative();
36
37
 
37
38
  private readonly stateListeners = new Set<(state: OnramperState) => void>();
38
39
  private readonly eventListeners = new Set<(event: CheckoutEvent) => void>();
40
+ private readonly transactionIdListeners = new Set<(transactionId: string | null) => void>();
39
41
 
40
42
  // Resolved when the constructor-issued configure() completes. Public methods
41
43
  // that need the native client await this first.
@@ -50,12 +52,23 @@ export class OnramperClient {
50
52
  for (const fn of this.stateListeners) fn(s);
51
53
  });
52
54
 
53
- // Single native checkout-event callback → fan out to listeners.
55
+ // Single native checkout-event callback → keep the transaction ID mirror
56
+ // synchronized at finalization, then fan out to checkout listeners.
54
57
  this.native.setEventListener((json) => {
55
58
  const e = JSON.parse(json) as CheckoutEvent;
59
+ if (e.type === 'checkoutFinalized') {
60
+ this.updateCurrentTransactionId(e.response.onramperTransactionId);
61
+ }
56
62
  for (const fn of this.eventListeners) fn(e);
57
63
  });
58
64
 
65
+ this.native.setTransactionIdListener((transactionId) => {
66
+ // The SDK transiently publishes nil while re-preparing after the payment
67
+ // sheet is dismissed. The finalized transaction ID remains durable across
68
+ // that attempt change; only explicit reset()/signOut() clear the JS mirror.
69
+ if (transactionId !== undefined) this.updateCurrentTransactionId(transactionId);
70
+ });
71
+
59
72
  // The SDK calls this when its session expires; return fresh credentials.
60
73
  // Nitro stores the async callback natively and awaits it directly — no
61
74
  // event round-trip needed.
@@ -82,6 +95,19 @@ export class OnramperClient {
82
95
  this.configured.catch(() => undefined);
83
96
  }
84
97
 
98
+ private updateCurrentTransactionId(next: string | null): void {
99
+ if (next === this.currentTransactionId) return;
100
+
101
+ this.currentTransactionId = next;
102
+ for (const fn of [...this.transactionIdListeners]) {
103
+ try {
104
+ fn(next);
105
+ } catch (error: unknown) {
106
+ console.error('Onramper transaction ID listener threw:', error);
107
+ }
108
+ }
109
+ }
110
+
85
111
  async initialize(creds: SessionCredentials): Promise<void> {
86
112
  try {
87
113
  await this.configured;
@@ -95,6 +121,7 @@ export class OnramperClient {
95
121
  try {
96
122
  await this.configured;
97
123
  await this.native.reset();
124
+ this.updateCurrentTransactionId(null);
98
125
  } catch (e: unknown) {
99
126
  throw OnramperError.from(e);
100
127
  }
@@ -110,6 +137,7 @@ export class OnramperClient {
110
137
  try {
111
138
  await this.configured;
112
139
  await this.native.signOut();
140
+ this.updateCurrentTransactionId(null);
113
141
  } catch (e: unknown) {
114
142
  throw OnramperError.from(e);
115
143
  }
@@ -143,10 +171,7 @@ export class OnramperClient {
143
171
  JSON.stringify(buttonStyle),
144
172
  );
145
173
  const quote = JSON.parse(result.quoteJson) as QuoteResponse;
146
- const button = createElement(OnramperCheckoutButtonView, {
147
- intentHandle: result.intentHandle,
148
- style: { width: '100%', minHeight: 56 },
149
- });
174
+ const button = createElement(CheckoutButton, { intentHandle: result.intentHandle });
150
175
  return { button, quote };
151
176
  } catch (e: unknown) {
152
177
  throw OnramperError.from(e);
@@ -166,6 +191,14 @@ export class OnramperClient {
166
191
  };
167
192
  }
168
193
 
194
+ /** Subscribe to the durable Onramper transaction ID. Successful reset/signOut publish null. */
195
+ addTransactionIdListener(fn: (transactionId: string | null) => void): () => void {
196
+ this.transactionIdListeners.add(fn);
197
+ return () => {
198
+ this.transactionIdListeners.delete(fn);
199
+ };
200
+ }
201
+
169
202
  /** Subscribe to a specific checkout event. Returns an unsubscribe function. */
170
203
  addEventListener<K extends EventName>(name: K, fn: (e: EventPayload<K>) => void): () => void {
171
204
  const wrapper = (e: CheckoutEvent) => {
@@ -181,6 +214,7 @@ export class OnramperClient {
181
214
  destroy(): void {
182
215
  this.stateListeners.clear();
183
216
  this.eventListeners.clear();
217
+ this.transactionIdListeners.clear();
184
218
  this.native.dispose();
185
219
  }
186
220
  }
@@ -5,6 +5,7 @@
5
5
  "directEventTypes": {},
6
6
  "validAttributes": {
7
7
  "intentHandle": true,
8
+ "onContentHeightChange": true,
8
9
  "hybridRef": true
9
10
  }
10
11
  }
@@ -5,6 +5,12 @@ import type { HybridView, HybridViewMethods, HybridViewProps } from 'react-nativ
5
5
  // UIHostingController. iOS-only (Android is a platformUnsupported stub).
6
6
  export interface OnramperCheckoutButtonProps extends HybridViewProps {
7
7
  intentHandle: string;
8
+ /**
9
+ * Called with the hosted SwiftUI content's height (points) whenever it changes —
10
+ * e.g. when ToS text appears under the Buy button. React Native can't measure
11
+ * the SwiftUI content itself, so the JS wrapper applies this as `height`.
12
+ */
13
+ onContentHeightChange?: (height: number) => void;
8
14
  }
9
15
 
10
16
  export interface OnramperCheckoutButtonMethods extends HybridViewMethods {}
@@ -52,6 +52,8 @@ export interface OnramperNitro extends HybridObject<{ ios: 'swift' }> {
52
52
  // Single native callback per stream; the JS wrapper fans out to multiple listeners.
53
53
  setStateListener(onState: (stateJson: string) => void): void;
54
54
  setEventListener(onEvent: (eventJson: string) => void): void;
55
+ // Mirrors OnramperSDK.$currentTransactionId. `undefined` represents native nil.
56
+ setTransactionIdListener(onTransactionId: (transactionId: string | undefined) => void): void;
55
57
 
56
58
  // The SDK's sessionExpirationHandler, as a stored async callback that returns
57
59
  // fresh credentials. Replaces the Expo-era onSessionExpired/provide/fail dance.
package/src/types.ts CHANGED
@@ -115,6 +115,8 @@ export interface HeadlessCheckoutData {
115
115
 
116
116
  export interface CheckoutFinalizeResponse {
117
117
  headlessCheckoutId: string;
118
+ /** Durable Onramper transaction identifier for support, reconciliation, and status lookups. */
119
+ onramperTransactionId: string;
118
120
  headlessCheckoutData: HeadlessCheckoutData;
119
121
  }
120
122