framepayments-react-native 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -191,6 +191,7 @@ if (result.status === 'completed') {
191
191
  |---|---|---|---|
192
192
  | `accountId` | `string` | No | The Frame account to onboard |
193
193
  | `capabilities` | `OnboardingCapability[]` | No | Which onboarding steps to include (see below) |
194
+ | `applePayMerchantId` | `string` | No | Apple Pay merchant ID. When set, the onboarding flow includes an Apple Pay setup step. iOS only — ignored on Android. Same prerequisites as `presentApplePay`. |
194
195
 
195
196
  **`capabilities` values:**
196
197
 
@@ -47,6 +47,12 @@ RCT_EXTERN_METHOD(presentOnboarding:(id)accountId
47
47
  resolver:(RCTPromiseResolveBlock)resolve
48
48
  rejecter:(RCTPromiseRejectBlock)reject)
49
49
 
50
+ RCT_EXTERN_METHOD(presentOnboardingWithApplePay:(id)accountId
51
+ capabilities:(NSArray *)capabilities
52
+ applePayMerchantId:(id)applePayMerchantId
53
+ resolver:(RCTPromiseResolveBlock)resolve
54
+ rejecter:(RCTPromiseRejectBlock)reject)
55
+
50
56
  RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
51
57
  ownerId:(NSString *)ownerId
52
58
  amount:(nonnull NSNumber *)amount
@@ -104,6 +110,17 @@ RCT_EXTERN_METHOD(presentApplePay:(NSString *)ownerType
104
110
  });
105
111
  }
106
112
 
113
+ - (void)presentOnboardingWithApplePay:(id)accountId capabilities:(NSArray *)capabilities applePayMerchantId:(id)applePayMerchantId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
114
+ dispatch_async(dispatch_get_main_queue(), ^{
115
+ UIViewController *topVC = FrameGetTopViewController();
116
+ if (!topVC) {
117
+ reject(@"NO_ROOT_VC", @"Could not find root view controller to present onboarding", nil);
118
+ return;
119
+ }
120
+ [[[ObjCFrameSDKBridge alloc] init] presentOnboardingWithApplePayFrom:topVC accountId:accountId capabilities:capabilities applePayMerchantId:applePayMerchantId resolver:resolve rejecter:reject];
121
+ });
122
+ }
123
+
107
124
  - (void)presentApplePay:(NSString *)ownerType ownerId:(NSString *)ownerId amount:(NSNumber *)amount currency:(NSString *)currency merchantId:(NSString *)merchantId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
108
125
  [[[ObjCFrameSDKBridge alloc] init] presentApplePay:ownerType ownerId:ownerId amount:amount.intValue currency:currency merchantId:merchantId resolver:resolve rejecter:reject];
109
126
  }
@@ -45,7 +45,15 @@ public class FrameSDKBridge: NSObject {
45
45
  func presentOnboarding(from viewController: UIViewController, accountId: NSObject?, capabilities: NSArray, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
46
46
  let parsedCapabilities = parseCapabilities(capabilities)
47
47
  let accountIdString = accountId as? String
48
- presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, resolve: resolve, reject: reject)
48
+ presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, applePayMerchantId: nil, resolve: resolve, reject: reject)
49
+ }
50
+
51
+ @objc public
52
+ func presentOnboardingWithApplePay(from viewController: UIViewController, accountId: NSObject?, capabilities: NSArray, applePayMerchantId: NSObject?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
53
+ let parsedCapabilities = parseCapabilities(capabilities)
54
+ let accountIdString = accountId as? String
55
+ let merchantIdString = applePayMerchantId as? String
56
+ presentOnboardingOnMain(from: viewController, accountId: accountIdString, capabilities: parsedCapabilities, applePayMerchantId: merchantIdString, resolve: resolve, reject: reject)
49
57
  }
50
58
 
51
59
  @objc public
@@ -179,13 +187,14 @@ public class FrameSDKBridge: NSObject {
179
187
  }
180
188
  }
181
189
 
182
- private func presentOnboardingOnMain(from top: UIViewController, accountId: String?, capabilities: [FrameObjects.Capabilities], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
190
+ private func presentOnboardingOnMain(from top: UIViewController, accountId: String?, capabilities: [FrameObjects.Capabilities], applePayMerchantId: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
183
191
  var hosting: OnboardingHostingController<OnboardingContainerView>!
184
192
  var delegate: OnboardingDismissDelegate!
185
193
  hosting = OnboardingHostingController(
186
194
  rootView: OnboardingContainerView(
187
195
  accountId: accountId,
188
196
  requiredCapabilities: capabilities,
197
+ applePayMerchantId: applePayMerchantId,
189
198
  onComplete: { [weak hosting] in
190
199
  delegate?.finish(completed: true)
191
200
  hosting?.dismiss(animated: true)
package/lib/native.d.ts CHANGED
@@ -19,6 +19,7 @@ export declare function presentCart(options: {
19
19
  export declare function presentOnboarding(options: {
20
20
  accountId?: string | null;
21
21
  capabilities?: OnboardingCapability[];
22
+ applePayMerchantId?: string | null;
22
23
  }): Promise<OnboardingResult>;
23
24
  export declare function presentApplePay(options: PresentApplePayOptions): Promise<ChargeIntent>;
24
25
  export declare function presentGooglePay(options: PresentGooglePayOptions): Promise<ChargeIntent>;
@@ -1 +1 @@
1
- {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAmBjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACvC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQ5B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBtF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC,CAUxF"}
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAmBjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiB5B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBtF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC,CAUxF"}
package/lib/native.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Native module bridge. Uses NativeModules for classic React Native bridge.
3
3
  */
4
- import { NativeModules } from 'react-native';
4
+ import { NativeModules, Platform } from 'react-native';
5
5
  import { ErrorCodes } from './errors';
6
6
  const LINKING_ERROR = `The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
7
7
  const FrameSDK = NativeModules.FrameSDK
@@ -53,6 +53,9 @@ export function presentCart(options) {
53
53
  }
54
54
  export function presentOnboarding(options) {
55
55
  guardInitialized();
56
+ if (Platform.OS === 'ios' && options.applePayMerchantId) {
57
+ return wrapPromise(FrameSDK.presentOnboardingWithApplePay(options.accountId ?? null, options.capabilities ?? [], options.applePayMerchantId));
58
+ }
56
59
  return wrapPromise(FrameSDK.presentOnboarding(options.accountId ?? null, options.capabilities ?? []));
57
60
  }
58
61
  export function presentApplePay(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "framepayments-react-native",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "React Native SDK for Frame Payments - modal checkout and cart, with API usage via frame-node.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -7,6 +7,9 @@ const mockInitialize = jest.fn((_secretKey: string, _publishableKey: string, _de
7
7
  const mockPresentCheckout = jest.fn((_customerId: unknown, _amount: number) => Promise.resolve({ id: 'ci_1', amount: 10000 }));
8
8
  const mockPresentCart = jest.fn((_customerId: unknown, _items: unknown[], _shipping: number) => Promise.resolve({ id: 'ci_2', amount: 15000 }));
9
9
  const mockPresentOnboarding = jest.fn((_accountId: unknown, _capabilities: unknown[]) => Promise.resolve({ status: 'completed', paymentMethodId: 'pm_1' }));
10
+ const mockPresentOnboardingWithApplePay = jest.fn((_accountId: unknown, _capabilities: unknown[], _merchantId: string) => Promise.resolve({ status: 'completed', paymentMethodId: 'pm_2' }));
11
+
12
+ const mockPlatform = { OS: 'ios' as 'ios' | 'android' };
10
13
 
11
14
  jest.mock('react-native', () => ({
12
15
  NativeModules: {
@@ -15,8 +18,10 @@ jest.mock('react-native', () => ({
15
18
  presentCheckout: mockPresentCheckout,
16
19
  presentCart: mockPresentCart,
17
20
  presentOnboarding: mockPresentOnboarding,
21
+ presentOnboardingWithApplePay: mockPresentOnboardingWithApplePay,
18
22
  },
19
23
  },
24
+ Platform: mockPlatform,
20
25
  }));
21
26
 
22
27
  // Re-import after mock so we get the mocked NativeModules
@@ -27,7 +32,7 @@ let presentCart: (opts: {
27
32
  items: Array<{ id: string; title: string; amountInCents: number; imageUrl: string }>;
28
33
  shippingAmountInCents: number;
29
34
  }) => Promise<unknown>;
30
- let presentOnboarding: (opts: { accountId?: string | null; capabilities?: string[] }) => Promise<unknown>;
35
+ let presentOnboarding: (opts: { accountId?: string | null; capabilities?: string[]; applePayMerchantId?: string | null }) => Promise<unknown>;
31
36
 
32
37
  beforeEach(() => {
33
38
  jest.resetModules();
@@ -35,6 +40,8 @@ beforeEach(() => {
35
40
  mockPresentCheckout.mockClear();
36
41
  mockPresentCart.mockClear();
37
42
  mockPresentOnboarding.mockClear();
43
+ mockPresentOnboardingWithApplePay.mockClear();
44
+ mockPlatform.OS = 'ios';
38
45
  const native = require('../native');
39
46
  initialize = native.initialize;
40
47
  presentCheckout = native.presentCheckout;
@@ -150,4 +157,20 @@ describe('presentOnboarding', () => {
150
157
  await presentOnboarding({});
151
158
  expect(mockPresentOnboarding).toHaveBeenCalledWith(null, []);
152
159
  });
160
+
161
+ it('routes to presentOnboardingWithApplePay on iOS when applePayMerchantId is set', async () => {
162
+ mockPlatform.OS = 'ios';
163
+ await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
164
+ await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc'], applePayMerchantId: 'merchant.com.example' });
165
+ expect(mockPresentOnboardingWithApplePay).toHaveBeenCalledWith('acct_1', ['kyc'], 'merchant.com.example');
166
+ expect(mockPresentOnboarding).not.toHaveBeenCalled();
167
+ });
168
+
169
+ it('still routes to presentOnboarding on Android even when applePayMerchantId is set', async () => {
170
+ mockPlatform.OS = 'android';
171
+ await initialize({ secretKey: 'sk_xxx', publishableKey: 'pk_xxx' });
172
+ await presentOnboarding({ accountId: 'acct_1', capabilities: ['kyc'], applePayMerchantId: 'merchant.com.example' });
173
+ expect(mockPresentOnboarding).toHaveBeenCalledWith('acct_1', ['kyc']);
174
+ expect(mockPresentOnboardingWithApplePay).not.toHaveBeenCalled();
175
+ });
153
176
  });
package/src/native.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Native module bridge. Uses NativeModules for classic React Native bridge.
3
3
  */
4
4
 
5
- import { NativeModules } from 'react-native';
5
+ import { NativeModules, Platform } from 'react-native';
6
6
  import type {
7
7
  ChargeIntent,
8
8
  FrameCartItem,
@@ -101,8 +101,18 @@ export function presentCart(options: {
101
101
  export function presentOnboarding(options: {
102
102
  accountId?: string | null;
103
103
  capabilities?: OnboardingCapability[];
104
+ applePayMerchantId?: string | null;
104
105
  }): Promise<OnboardingResult> {
105
106
  guardInitialized();
107
+ if (Platform.OS === 'ios' && options.applePayMerchantId) {
108
+ return wrapPromise(
109
+ FrameSDK.presentOnboardingWithApplePay(
110
+ options.accountId ?? null,
111
+ options.capabilities ?? [],
112
+ options.applePayMerchantId
113
+ )
114
+ );
115
+ }
106
116
  return wrapPromise(
107
117
  FrameSDK.presentOnboarding(
108
118
  options.accountId ?? null,