@onramper/onramper-react-native 1.0.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 (163) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +5 -0
  4. package/OnramperReactNative.podspec +36 -0
  5. package/README.md +114 -0
  6. package/app.plugin.js +51 -0
  7. package/ios/Frameworks/LICENSE +202 -0
  8. package/ios/Frameworks/NOTICE +5 -0
  9. package/ios/Frameworks/OnramperSDK.xcframework/Info.plist +48 -0
  10. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Info.plist +0 -0
  11. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  12. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios.swiftinterface +548 -0
  13. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK +0 -0
  14. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/Info.plist +0 -0
  15. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/PrivacyInfo.xcprivacy +27 -0
  16. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/OnramperSDK.framework/PrivacyInfo.xcprivacy +27 -0
  17. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Info.plist +20 -0
  18. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  19. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +2518 -0
  20. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Info.plist +0 -0
  21. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  22. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +548 -0
  23. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  24. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/Modules/OnramperSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +548 -0
  25. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK +0 -0
  26. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/Info.plist +0 -0
  27. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/OnramperSDK_OnramperSDK.bundle/PrivacyInfo.xcprivacy +27 -0
  28. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/OnramperSDK.framework/PrivacyInfo.xcprivacy +27 -0
  29. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Info.plist +20 -0
  30. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/DWARF/OnramperSDK +0 -0
  31. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/OnramperSDK.yml +2518 -0
  32. package/ios/Frameworks/OnramperSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/OnramperSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/OnramperSDK.yml +2487 -0
  33. package/ios/HybridOnramperCheckoutButton.swift +112 -0
  34. package/ios/HybridOnramperNitro.swift +194 -0
  35. package/ios/OnramperCheckoutBridge.swift +88 -0
  36. package/ios/OnramperSDKBridge.swift +185 -0
  37. package/ios/PreparedIntentRegistry.swift +78 -0
  38. package/lib/commonjs/OnramperCheckoutButtonView.js +16 -0
  39. package/lib/commonjs/OnramperCheckoutButtonView.js.map +1 -0
  40. package/lib/commonjs/OnramperClient.js +161 -0
  41. package/lib/commonjs/OnramperClient.js.map +1 -0
  42. package/lib/commonjs/OnramperNative.js +22 -0
  43. package/lib/commonjs/OnramperNative.js.map +1 -0
  44. package/lib/commonjs/errors.js +35 -0
  45. package/lib/commonjs/errors.js.map +1 -0
  46. package/lib/commonjs/events.js +6 -0
  47. package/lib/commonjs/events.js.map +1 -0
  48. package/lib/commonjs/generated/OnramperCheckoutButtonConfig.json +10 -0
  49. package/lib/commonjs/index.js +27 -0
  50. package/lib/commonjs/index.js.map +1 -0
  51. package/lib/commonjs/package.json +1 -0
  52. package/lib/commonjs/specs/OnramperCheckoutButton.nitro.js +6 -0
  53. package/lib/commonjs/specs/OnramperCheckoutButton.nitro.js.map +1 -0
  54. package/lib/commonjs/specs/OnramperNitro.nitro.js +6 -0
  55. package/lib/commonjs/specs/OnramperNitro.nitro.js.map +1 -0
  56. package/lib/commonjs/types.js +6 -0
  57. package/lib/commonjs/types.js.map +1 -0
  58. package/lib/module/OnramperCheckoutButtonView.js +11 -0
  59. package/lib/module/OnramperCheckoutButtonView.js.map +1 -0
  60. package/lib/module/OnramperClient.js +156 -0
  61. package/lib/module/OnramperClient.js.map +1 -0
  62. package/lib/module/OnramperNative.js +18 -0
  63. package/lib/module/OnramperNative.js.map +1 -0
  64. package/lib/module/errors.js +30 -0
  65. package/lib/module/errors.js.map +1 -0
  66. package/lib/module/events.js +4 -0
  67. package/lib/module/events.js.map +1 -0
  68. package/lib/module/generated/OnramperCheckoutButtonConfig.json +10 -0
  69. package/lib/module/index.js +8 -0
  70. package/lib/module/index.js.map +1 -0
  71. package/lib/module/package.json +1 -0
  72. package/lib/module/specs/OnramperCheckoutButton.nitro.js +4 -0
  73. package/lib/module/specs/OnramperCheckoutButton.nitro.js.map +1 -0
  74. package/lib/module/specs/OnramperNitro.nitro.js +4 -0
  75. package/lib/module/specs/OnramperNitro.nitro.js.map +1 -0
  76. package/lib/module/types.js +4 -0
  77. package/lib/module/types.js.map +1 -0
  78. package/lib/typescript/commonjs/package.json +1 -0
  79. package/lib/typescript/commonjs/src/OnramperCheckoutButtonView.d.ts +9 -0
  80. package/lib/typescript/commonjs/src/OnramperCheckoutButtonView.d.ts.map +1 -0
  81. package/lib/typescript/commonjs/src/OnramperClient.d.ts +49 -0
  82. package/lib/typescript/commonjs/src/OnramperClient.d.ts.map +1 -0
  83. package/lib/typescript/commonjs/src/OnramperNative.d.ts +9 -0
  84. package/lib/typescript/commonjs/src/OnramperNative.d.ts.map +1 -0
  85. package/lib/typescript/commonjs/src/errors.d.ts +13 -0
  86. package/lib/typescript/commonjs/src/errors.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/src/events.d.ts +48 -0
  88. package/lib/typescript/commonjs/src/events.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/src/index.d.ts +9 -0
  90. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts +10 -0
  92. package/lib/typescript/commonjs/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts +39 -0
  94. package/lib/typescript/commonjs/src/specs/OnramperNitro.nitro.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/src/types.d.ts +127 -0
  96. package/lib/typescript/commonjs/src/types.d.ts.map +1 -0
  97. package/lib/typescript/module/package.json +1 -0
  98. package/lib/typescript/module/src/OnramperCheckoutButtonView.d.ts +9 -0
  99. package/lib/typescript/module/src/OnramperCheckoutButtonView.d.ts.map +1 -0
  100. package/lib/typescript/module/src/OnramperClient.d.ts +49 -0
  101. package/lib/typescript/module/src/OnramperClient.d.ts.map +1 -0
  102. package/lib/typescript/module/src/OnramperNative.d.ts +9 -0
  103. package/lib/typescript/module/src/OnramperNative.d.ts.map +1 -0
  104. package/lib/typescript/module/src/errors.d.ts +13 -0
  105. package/lib/typescript/module/src/errors.d.ts.map +1 -0
  106. package/lib/typescript/module/src/events.d.ts +48 -0
  107. package/lib/typescript/module/src/events.d.ts.map +1 -0
  108. package/lib/typescript/module/src/index.d.ts +9 -0
  109. package/lib/typescript/module/src/index.d.ts.map +1 -0
  110. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts +10 -0
  111. package/lib/typescript/module/src/specs/OnramperCheckoutButton.nitro.d.ts.map +1 -0
  112. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts +39 -0
  113. package/lib/typescript/module/src/specs/OnramperNitro.nitro.d.ts.map +1 -0
  114. package/lib/typescript/module/src/types.d.ts +127 -0
  115. package/lib/typescript/module/src/types.d.ts.map +1 -0
  116. package/nitro.json +19 -0
  117. package/nitrogen/generated/.gitattributes +1 -0
  118. package/nitrogen/generated/ios/OnramperReactNative+autolinking.rb +62 -0
  119. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.cpp +107 -0
  120. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Bridge.hpp +299 -0
  121. package/nitrogen/generated/ios/OnramperReactNative-Swift-Cxx-Umbrella.hpp +60 -0
  122. package/nitrogen/generated/ios/OnramperReactNativeAutolinking.mm +41 -0
  123. package/nitrogen/generated/ios/OnramperReactNativeAutolinking.swift +38 -0
  124. package/nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.cpp +11 -0
  125. package/nitrogen/generated/ios/c++/HybridOnramperCheckoutButtonSpecSwift.hpp +81 -0
  126. package/nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.cpp +11 -0
  127. package/nitrogen/generated/ios/c++/HybridOnramperNitroSpecSwift.hpp +150 -0
  128. package/nitrogen/generated/ios/c++/views/HybridOnramperCheckoutButtonComponent.mm +122 -0
  129. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_NitroSessionCredentials____.swift +61 -0
  130. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  131. package/nitrogen/generated/ios/swift/Func_void_NitroSessionCredentials.swift +46 -0
  132. package/nitrogen/generated/ios/swift/Func_void_PreparedIntentResult.swift +46 -0
  133. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  134. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_NitroSessionCredentials__.swift +66 -0
  135. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  136. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec.swift +55 -0
  137. package/nitrogen/generated/ios/swift/HybridOnramperCheckoutButtonSpec_cxx.swift +156 -0
  138. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec.swift +63 -0
  139. package/nitrogen/generated/ios/swift/HybridOnramperNitroSpec_cxx.swift +309 -0
  140. package/nitrogen/generated/ios/swift/NitroSessionCredentials.swift +34 -0
  141. package/nitrogen/generated/ios/swift/OnramperNitroConfig.swift +49 -0
  142. package/nitrogen/generated/ios/swift/PreparedIntentResult.swift +34 -0
  143. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.cpp +22 -0
  144. package/nitrogen/generated/shared/c++/HybridOnramperCheckoutButtonSpec.hpp +63 -0
  145. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.cpp +29 -0
  146. package/nitrogen/generated/shared/c++/HybridOnramperNitroSpec.hpp +80 -0
  147. package/nitrogen/generated/shared/c++/NitroSessionCredentials.hpp +87 -0
  148. package/nitrogen/generated/shared/c++/OnramperNitroConfig.hpp +99 -0
  149. package/nitrogen/generated/shared/c++/PreparedIntentResult.hpp +87 -0
  150. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.cpp +83 -0
  151. package/nitrogen/generated/shared/c++/views/HybridOnramperCheckoutButtonComponent.hpp +111 -0
  152. package/nitrogen/generated/shared/json/OnramperCheckoutButtonConfig.json +10 -0
  153. package/package.json +107 -0
  154. package/src/OnramperCheckoutButtonView.tsx +15 -0
  155. package/src/OnramperClient.ts +170 -0
  156. package/src/OnramperNative.ts +19 -0
  157. package/src/errors.ts +69 -0
  158. package/src/events.ts +23 -0
  159. package/src/generated/OnramperCheckoutButtonConfig.json +10 -0
  160. package/src/index.ts +30 -0
  161. package/src/specs/OnramperCheckoutButton.nitro.ts +16 -0
  162. package/src/specs/OnramperNitro.nitro.ts +60 -0
  163. package/src/types.ts +133 -0
@@ -0,0 +1,170 @@
1
+ import { type ReactElement, createElement } from 'react';
2
+
3
+ import { OnramperCheckoutButtonView } from './OnramperCheckoutButtonView';
4
+ import { createOnramperNative } from './OnramperNative';
5
+ import { OnramperError } from './errors';
6
+ import type { CheckoutEvent, EventName, EventPayload } from './events';
7
+ import type {
8
+ CheckoutButtonStyle,
9
+ CheckoutRequest,
10
+ OnramperConfiguration,
11
+ OnramperState,
12
+ QuoteResponse,
13
+ SessionCredentials,
14
+ } from './types';
15
+
16
+ export interface GetCheckoutRequirementsResult {
17
+ /** A native checkout button element to render. Tapping it drives login, finalize, and the payment webview internally. */
18
+ button: ReactElement;
19
+ /** The quote (rate, fees, payout) returned with the checkout intent. */
20
+ quote: QuoteResponse;
21
+ }
22
+
23
+ /**
24
+ * Typed, public entry point to the Onramper SDK. Wraps the native Nitro hybrid
25
+ * object: state and checkout events arrive as JSON strings over single native
26
+ * callbacks and are parsed here into the typed `OnramperState` / `CheckoutEvent`
27
+ * unions, then fanned out to any number of listeners.
28
+ */
29
+ export class OnramperClient {
30
+ state: OnramperState = { kind: 'idle' };
31
+ lastError: OnramperError | null = null;
32
+
33
+ // Each client owns its own native instance (and thus its own SDK client).
34
+ private readonly native = createOnramperNative();
35
+
36
+ private readonly stateListeners = new Set<(state: OnramperState) => void>();
37
+ private readonly eventListeners = new Set<(event: CheckoutEvent) => void>();
38
+
39
+ // Resolved when the constructor-issued configure() completes. Public methods
40
+ // that need the native client await this first.
41
+ private readonly configured: Promise<void>;
42
+
43
+ constructor(config: OnramperConfiguration) {
44
+ // Single native state callback → update the mirror + fan out to listeners.
45
+ this.native.setStateListener((json) => {
46
+ const s = JSON.parse(json) as OnramperState;
47
+ this.state = s;
48
+ if (s.kind === 'failed') this.lastError = OnramperError.from(s.error);
49
+ for (const fn of this.stateListeners) fn(s);
50
+ });
51
+
52
+ // Single native checkout-event callback → fan out to listeners.
53
+ this.native.setEventListener((json) => {
54
+ const e = JSON.parse(json) as CheckoutEvent;
55
+ for (const fn of this.eventListeners) fn(e);
56
+ });
57
+
58
+ // The SDK calls this when its session expires; return fresh credentials.
59
+ // Nitro stores the async callback natively and awaits it directly — no
60
+ // event round-trip needed.
61
+ this.native.setSessionExpirationHandler(async () => {
62
+ const creds = await config.onSessionExpired();
63
+ return { sessionId: creds.sessionId, sessionToken: creds.sessionToken };
64
+ });
65
+
66
+ this.configured = this.native
67
+ .configure({
68
+ apiKey: config.apiKey,
69
+ clientId: config.clientId,
70
+ environment: config.environment,
71
+ theme: config.theme ?? 'system',
72
+ logLevel: config.logLevel ?? 'off',
73
+ })
74
+ .catch((e: unknown) => {
75
+ const err = OnramperError.from(e);
76
+ this.lastError = err;
77
+ throw err;
78
+ });
79
+ // Swallow the unhandled-rejection warning when no one awaits .configured
80
+ // before calling initialize(). The error still surfaces via initialize().
81
+ this.configured.catch(() => undefined);
82
+ }
83
+
84
+ async initialize(creds: SessionCredentials): Promise<void> {
85
+ try {
86
+ await this.configured;
87
+ await this.native.initialize(creds.sessionId, creds.sessionToken);
88
+ } catch (e: unknown) {
89
+ throw OnramperError.from(e);
90
+ }
91
+ }
92
+
93
+ async reset(): Promise<void> {
94
+ try {
95
+ await this.configured;
96
+ await this.native.reset();
97
+ } catch (e: unknown) {
98
+ throw OnramperError.from(e);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Signs the OnramperID user out by clearing stored OIDC tokens. The next
104
+ * checkout that requires user_info will re-trigger the login flow. Also
105
+ * resets in-flight checkout state. Does NOT clear the partner-scoped SDK
106
+ * session — re-calling `initialize` is only needed if that session expired.
107
+ */
108
+ async signOut(): Promise<void> {
109
+ try {
110
+ await this.configured;
111
+ await this.native.signOut();
112
+ } catch (e: unknown) {
113
+ throw OnramperError.from(e);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Fetches checkout requirements + quote and returns a native checkout button
119
+ * to render plus the quote. The button handles login / finalize / webview
120
+ * internally; outcomes surface via the event stream (`addEventListener`).
121
+ */
122
+ async getCheckoutRequirements(
123
+ request: CheckoutRequest,
124
+ buttonStyle: CheckoutButtonStyle = {},
125
+ ): Promise<GetCheckoutRequirementsResult> {
126
+ try {
127
+ await this.configured;
128
+ const result = await this.native.getCheckoutRequirements(JSON.stringify(request), JSON.stringify(buttonStyle));
129
+ const quote = JSON.parse(result.quoteJson) as QuoteResponse;
130
+ const button = createElement(OnramperCheckoutButtonView, {
131
+ intentHandle: result.intentHandle,
132
+ style: { width: '100%', minHeight: 56 },
133
+ });
134
+ return { button, quote };
135
+ } catch (e: unknown) {
136
+ throw OnramperError.from(e);
137
+ }
138
+ }
139
+
140
+ /** Discards a prepared intent (e.g. if the user navigates away before checkout). */
141
+ cancelPreparedIntent(intentHandle: string): Promise<void> {
142
+ return this.native.cancelPreparedIntent(intentHandle);
143
+ }
144
+
145
+ /** Subscribe to state changes. Returns an unsubscribe function. */
146
+ addStateListener(fn: (state: OnramperState) => void): () => void {
147
+ this.stateListeners.add(fn);
148
+ return () => {
149
+ this.stateListeners.delete(fn);
150
+ };
151
+ }
152
+
153
+ /** Subscribe to a specific checkout event. Returns an unsubscribe function. */
154
+ addEventListener<K extends EventName>(name: K, fn: (e: EventPayload<K>) => void): () => void {
155
+ const wrapper = (e: CheckoutEvent) => {
156
+ if (e.type === name) fn(e as EventPayload<K>);
157
+ };
158
+ this.eventListeners.add(wrapper);
159
+ return () => {
160
+ this.eventListeners.delete(wrapper);
161
+ };
162
+ }
163
+
164
+ /** Tear down: clears JS listeners and releases the native callbacks + SDK client. */
165
+ destroy(): void {
166
+ this.stateListeners.clear();
167
+ this.eventListeners.clear();
168
+ this.native.dispose();
169
+ }
170
+ }
@@ -0,0 +1,19 @@
1
+ import { Platform } from 'react-native';
2
+ import { NitroModules } from 'react-native-nitro-modules';
3
+ import type { OnramperNitro } from './specs/OnramperNitro.nitro';
4
+
5
+ /**
6
+ * Creates a fresh native Onramper Nitro hybrid object. Each `OnramperClient`
7
+ * owns its own instance, so its listeners and the underlying SDK client are
8
+ * isolated per client and torn down by `destroy()` → `dispose()`.
9
+ */
10
+ export function createOnramperNative(): OnramperNitro {
11
+ // iOS-only in this release. Fail with a clear message rather than the opaque
12
+ // "hybrid object not found" Nitro would throw on platforms without a native impl.
13
+ if (Platform.OS !== 'ios') {
14
+ throw new Error(`Onramper React Native is iOS-only in this release; it is not supported on ${Platform.OS}.`);
15
+ }
16
+ return NitroModules.createHybridObject<OnramperNitro>('OnramperNitro');
17
+ }
18
+
19
+ export type { OnramperNitro };
package/src/errors.ts ADDED
@@ -0,0 +1,69 @@
1
+ export type OnramperErrorCode =
2
+ // Mirrors Sources/OnramperSDK/Errors/OnramperError.swift cases
3
+ | 'notInitialized'
4
+ | 'initializationFailed'
5
+ | 'attestationFailed'
6
+ | 'invalidStateTransition'
7
+ | 'invalidState'
8
+ | 'networkError'
9
+ | 'decodingError'
10
+ | 'timeout'
11
+ | 'requirementNotSatisfied'
12
+ | 'amountOutOfRange'
13
+ | 'oidcFlowCancelled'
14
+ | 'oidcTokenExchangeFailed'
15
+ | 'oidcFlowFailed'
16
+ | 'userTokenInvalid'
17
+ | 'userTokenRefreshFailed'
18
+ | 'webviewLoadFailed'
19
+ | 'deepLinkFailed'
20
+ | 'invalidRequest'
21
+ | 'quoteUnavailable'
22
+ | 'checkoutForbidden'
23
+ | 'temporaryFailure'
24
+ | 'unrecoverable'
25
+ | 'configurationError'
26
+ | 'deviceBlocked'
27
+ | 'securityStorageFailed'
28
+ | 'securityTrustFailed'
29
+ // JS-only codes
30
+ | 'platformUnsupported'
31
+ | 'intentInvalidated'
32
+ | 'intentAlreadyConsumed'
33
+ | 'clientAlreadyConfigured'
34
+ | 'sessionExpirationHandlerFailed';
35
+
36
+ export interface OnramperErrorPayload {
37
+ code: OnramperErrorCode;
38
+ message: string;
39
+ info?: Record<string, unknown>;
40
+ }
41
+
42
+ export class OnramperError extends Error implements OnramperErrorPayload {
43
+ readonly code: OnramperErrorCode;
44
+ readonly info?: Record<string, unknown>;
45
+
46
+ constructor(payload: OnramperErrorPayload) {
47
+ super(payload.message);
48
+ this.name = 'OnramperError';
49
+ this.code = payload.code;
50
+ this.info = payload.info;
51
+ }
52
+
53
+ static from(value: unknown): OnramperError {
54
+ if (value instanceof OnramperError) return value;
55
+ if (value && typeof value === 'object') {
56
+ // Structured errors (from the `.failed` state) arrive as a plain
57
+ // `{ code, message, info? }` object. Thrown promise rejections surface
58
+ // as a JS Error with just a message; we default the code in that case
59
+ // (the structured error is also available on `client.state` / lastError).
60
+ const v = value as { code?: string; message?: string; info?: Record<string, unknown> };
61
+ return new OnramperError({
62
+ code: (v.code ?? 'unrecoverable') as OnramperErrorCode,
63
+ message: v.message ?? 'Unknown error',
64
+ info: v.info,
65
+ });
66
+ }
67
+ return new OnramperError({ code: 'unrecoverable', message: String(value) });
68
+ }
69
+ }
package/src/events.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { OnramperErrorPayload } from './errors';
2
+ import type { CheckoutFinalizeResponse, CheckoutRequirement, OnramperState, RenderType } from './types';
3
+
4
+ export type CheckoutEvent =
5
+ | { type: 'stateChanged'; state: OnramperState }
6
+ | { type: 'checkoutStarted'; intentId: string }
7
+ | { type: 'loginRequired'; requirements: CheckoutRequirement[] }
8
+ | { type: 'readyToCheckout' }
9
+ | { type: 'requirementSatisfied'; requirementType: string }
10
+ | { type: 'checkoutFinalized'; response: CheckoutFinalizeResponse }
11
+ | { type: 'renderingStarted'; url: string; renderType: RenderType }
12
+ | { type: 'completed'; checkoutId: string }
13
+ | { type: 'failed'; error: OnramperErrorPayload }
14
+ | { type: 'cancelled' }
15
+ // Provider-lifecycle events from third-party checkout webviews.
16
+ | { type: 'providerReady' }
17
+ | { type: 'paymentAuthorized' }
18
+ | { type: 'paymentProcessing' }
19
+ | { type: 'paymentCancelled' }
20
+ | { type: 'providerError'; reason: string };
21
+
22
+ export type EventName = CheckoutEvent['type'];
23
+ export type EventPayload<K extends EventName> = Extract<CheckoutEvent, { type: K }>;
@@ -0,0 +1,10 @@
1
+ {
2
+ "uiViewClassName": "OnramperCheckoutButton",
3
+ "supportsRawText": false,
4
+ "bubblingEventTypes": {},
5
+ "directEventTypes": {},
6
+ "validAttributes": {
7
+ "intentHandle": true,
8
+ "hybridRef": true
9
+ }
10
+ }
package/src/index.ts ADDED
@@ -0,0 +1,30 @@
1
+ // Public API re-exports.
2
+
3
+ export { OnramperClient } from './OnramperClient';
4
+ export type { GetCheckoutRequirementsResult } from './OnramperClient';
5
+ export { OnramperCheckoutButtonView } from './OnramperCheckoutButtonView';
6
+ export type { OnramperCheckoutButtonViewProps } from './OnramperCheckoutButtonView';
7
+ export { OnramperError } from './errors';
8
+ export type { OnramperErrorCode, OnramperErrorPayload } from './errors';
9
+ export type {
10
+ CheckoutButtonStyle,
11
+ CheckoutFinalizeResponse,
12
+ CheckoutRequest,
13
+ CheckoutPaymentType,
14
+ CheckoutRequirement,
15
+ HeadlessCheckoutData,
16
+ OnramperConfiguration,
17
+ OnramperEnvironment,
18
+ OnramperLogLevel,
19
+ OnramperState,
20
+ OnramperTheme,
21
+ QuoteError,
22
+ QuoteResponse,
23
+ RenderType,
24
+ SessionCredentials,
25
+ ToSItem,
26
+ TransactionType,
27
+ UserInfoField,
28
+ WalletInfo,
29
+ } from './types';
30
+ export type { CheckoutEvent, EventName, EventPayload } from './events';
@@ -0,0 +1,16 @@
1
+ import type { HybridView, HybridViewMethods, HybridViewProps } from 'react-native-nitro-modules';
2
+
3
+ // The native checkout button. Renders the SwiftUI OnramperCheckoutButton that
4
+ // getCheckoutRequirements() stashed under `intentHandle`, hosted via
5
+ // UIHostingController. iOS-only (Android is a platformUnsupported stub).
6
+ export interface OnramperCheckoutButtonProps extends HybridViewProps {
7
+ intentHandle: string;
8
+ }
9
+
10
+ export interface OnramperCheckoutButtonMethods extends HybridViewMethods {}
11
+
12
+ export type OnramperCheckoutButton = HybridView<
13
+ OnramperCheckoutButtonProps,
14
+ OnramperCheckoutButtonMethods,
15
+ { ios: 'swift' }
16
+ >;
@@ -0,0 +1,60 @@
1
+ import type { HybridObject } from 'react-native-nitro-modules';
2
+
3
+ // Plain config passed to configure(). String unions are validated on the Swift
4
+ // side against the SDK's Environment/Theme/LogLevel enums.
5
+ export interface OnramperNitroConfig {
6
+ apiKey: string;
7
+ clientId: string;
8
+ environment: string; // 'development' | 'production'
9
+ theme: string; // 'system' | 'light' | 'dark'
10
+ logLevel: string; // 'off' | 'error' | 'info' | 'debug'
11
+ }
12
+
13
+ // Mirrors OnramperSDK.SessionCredentials. Named with a Nitro prefix to avoid a
14
+ // Swift type clash with the SDK's own `SessionCredentials`.
15
+ export interface NitroSessionCredentials {
16
+ sessionId: string;
17
+ sessionToken: string;
18
+ }
19
+
20
+ // Result of getCheckoutRequirements: a handle the OnramperCheckoutButton view
21
+ // renders by, plus the quote (JSON-encoded QuoteResponse, parsed in JS).
22
+ export interface PreparedIntentResult {
23
+ intentHandle: string;
24
+ quoteJson: string;
25
+ }
26
+
27
+ /**
28
+ * Native bridge to OnramperSDK's `OnramperClient`. The public, typed JS API
29
+ * (`OnramperClient`) wraps this.
30
+ *
31
+ * State and checkout events are delivered as JSON strings (the SDK's
32
+ * `OnramperState`/`CheckoutEvent` are non-Codable Swift enums; the Swift side
33
+ * hand-maps each case to a dict and JSON-encodes it). The JS wrapper parses
34
+ * them back into the fully-typed `OnramperState`/`CheckoutEvent` unions.
35
+ */
36
+ export interface OnramperNitro extends HybridObject<{ ios: 'swift' }> {
37
+ configure(config: OnramperNitroConfig): Promise<void>;
38
+ initialize(sessionId: string, sessionToken: string): Promise<void>;
39
+ reset(): Promise<void>;
40
+ signOut(): Promise<void>;
41
+
42
+ // Fetches checkout requirements + quote, stores the SDK's SwiftUI checkout
43
+ // button under a handle, and returns the handle + JSON-encoded quote. The
44
+ // OnramperCheckoutButton Nitro view renders the stored button by handle.
45
+ // `requestJson` is a JSON CheckoutRequest; `styleJson` a JSON CheckoutButtonStyle.
46
+ getCheckoutRequirements(requestJson: string, styleJson: string): Promise<PreparedIntentResult>;
47
+ cancelPreparedIntent(intentHandle: string): Promise<void>;
48
+
49
+ // Single native callback per stream; the JS wrapper fans out to multiple listeners.
50
+ setStateListener(onState: (stateJson: string) => void): void;
51
+ setEventListener(onEvent: (eventJson: string) => void): void;
52
+
53
+ // The SDK's sessionExpirationHandler, as a stored async callback that returns
54
+ // fresh credentials. Replaces the Expo-era onSessionExpired/provide/fail dance.
55
+ setSessionExpirationHandler(handler: () => Promise<NitroSessionCredentials>): void;
56
+
57
+ // NOTE: every HybridObject has a built-in `dispose()`; we override it natively
58
+ // (in HybridOnramperNitro.swift) to release stored callbacks + the SDK client.
59
+ // It must NOT be declared here — nitrogen rejects re-declaring dispose().
60
+ }
package/src/types.ts ADDED
@@ -0,0 +1,133 @@
1
+ // Mirrors Swift Codable structs in OnramperSDK. Source of truth is the Swift SDK
2
+ // at the bundled version. Do not add fields that don't exist there.
3
+
4
+ import type { OnramperErrorPayload } from './errors';
5
+
6
+ export type OnramperEnvironment = 'development' | 'production';
7
+ export type OnramperLogLevel = 'off' | 'error' | 'info' | 'debug';
8
+ export type OnramperTheme = 'system' | 'light' | 'dark';
9
+
10
+ export type TransactionType = 'buy' | 'sell';
11
+
12
+ export interface SessionCredentials {
13
+ sessionId: string;
14
+ sessionToken: string;
15
+ }
16
+
17
+ export interface OnramperConfiguration {
18
+ apiKey: string;
19
+ clientId: string;
20
+ environment: OnramperEnvironment;
21
+ theme?: OnramperTheme;
22
+ logLevel?: OnramperLogLevel;
23
+ /**
24
+ * Called by the SDK when the session token expires and needs to be re-issued.
25
+ *
26
+ * May be synchronous or async — under the hood the bridge uses an event
27
+ * round-trip (`onSessionExpired` → `provideSessionCredentials`) so Promises
28
+ * are awaited normally. Throw or reject to signal that no fresh credentials
29
+ * are available; the SDK will surface `userTokenRefreshFailed`.
30
+ */
31
+ onSessionExpired: () => SessionCredentials | Promise<SessionCredentials>;
32
+ }
33
+
34
+ export interface WalletInfo {
35
+ network: string;
36
+ address: string;
37
+ memo?: string;
38
+ }
39
+
40
+ // Flattened from the Swift nesting (CheckoutIntentRequest → OnramperTransactionData).
41
+ // The bridge re-nests before handing to the SDK. ISO codes (`source`, `destination`,
42
+ // `country`, `subdivision`) are lowercased by the SDK; pass either case.
43
+ export interface CheckoutRequest {
44
+ source: string;
45
+ destination?: string;
46
+ amount: number;
47
+ type: TransactionType;
48
+ country?: string;
49
+ subdivision?: string;
50
+ paymentMethod: string;
51
+ wallet: WalletInfo;
52
+ onlyOnramps?: string[];
53
+ }
54
+
55
+ // Mirrors Swift QuoteResponse exactly — all fields optional because the BFF
56
+ // can return a partial quote with `errors` populated when the onramp can't
57
+ // honor the request. Integrators must handle nulls.
58
+ export interface QuoteResponse {
59
+ quoteId?: string;
60
+ ramp?: string;
61
+ rate?: number;
62
+ networkFee?: number;
63
+ transactionFee?: number;
64
+ payout?: number;
65
+ paymentMethod?: string;
66
+ recommendations?: string[];
67
+ errors?: QuoteError[];
68
+ }
69
+
70
+ export interface QuoteError {
71
+ type: string;
72
+ message: string;
73
+ }
74
+
75
+ export interface CheckoutButtonStyle {
76
+ backgroundColor?: string; // hex #RRGGBB or #RRGGBBAA
77
+ foregroundColor?: string;
78
+ borderRadius?: number;
79
+ }
80
+
81
+ // Mirrors Swift `RenderType` raw values from Models/SharedTypes.swift.
82
+ export type RenderType = 'webview' | 'deeplink';
83
+ // Mirrors Swift `CheckoutPaymentType` raw values from Models/SharedTypes.swift.
84
+ export type CheckoutPaymentType = 'applepay' | 'revolutpay';
85
+
86
+ // Mirrors Swift `CheckoutFinalizeResponse` / `HeadlessCheckoutData`
87
+ // (Sources/OnramperSDK/Models/CheckoutFinalizeResponse.swift).
88
+ export interface HeadlessCheckoutData {
89
+ checkoutPaymentType: CheckoutPaymentType;
90
+ url: string;
91
+ renderType: RenderType;
92
+ }
93
+
94
+ export interface CheckoutFinalizeResponse {
95
+ headlessCheckoutId: string;
96
+ headlessCheckoutData: HeadlessCheckoutData;
97
+ }
98
+
99
+ // Checkout requirements surfaced by the BFF and bridged through JSON.
100
+ // Shape mirrors Sources/OnramperSDK/Models/CheckoutIntentResponse.swift.
101
+ export type CheckoutRequirement =
102
+ | { type: 'tos'; providerId: string; items: ToSItem[] }
103
+ | { type: 'amount_limit'; providerId: string; minAmountLimit?: number; maxAmountLimit?: number }
104
+ | { type: 'user_info'; providerId: string; fields: UserInfoField[] };
105
+
106
+ export interface ToSItem {
107
+ type: 'tos' | 'privacy_policy' | 'user_agreement';
108
+ required: boolean;
109
+ satisfied: boolean;
110
+ url?: string;
111
+ content?: string;
112
+ }
113
+
114
+ export interface UserInfoField {
115
+ type: string; // backend can extend; safer to leave open
116
+ required: boolean;
117
+ // other fields omitted for v1 — extend later if needed
118
+ }
119
+
120
+ export type OnramperState =
121
+ | { kind: 'idle' }
122
+ | { kind: 'initializing' }
123
+ | { kind: 'ready' }
124
+ | { kind: 'checkoutPreparing' }
125
+ | { kind: 'requireLogin'; requirements: CheckoutRequirement[] }
126
+ | { kind: 'authenticating' }
127
+ | { kind: 'readyToCheckout' }
128
+ | { kind: 'finalizing' }
129
+ | { kind: 'rendering'; url: string; renderType: RenderType; paymentType: CheckoutPaymentType }
130
+ | { kind: 'completed' }
131
+ | { kind: 'failed'; error: OnramperErrorPayload };
132
+
133
+ export type { OnramperErrorPayload };