vialink-react-native-sdk 2.0.15 → 2.1.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.
Binary file
@@ -4,6 +4,7 @@ import com.facebook.react.bridge.*
4
4
  import com.facebook.react.modules.core.DeviceEventManagerModule
5
5
  import com.vialink.sdk.ViaLinkSDK
6
6
  import com.vialink.sdk.model.DeepLinkData
7
+ import com.vialink.sdk.model.PaymentInitiatedArgs
7
8
  import kotlinx.coroutines.*
8
9
 
9
10
  class ViaLinkModule(reactContext: ReactApplicationContext) :
@@ -11,7 +12,7 @@ class ViaLinkModule(reactContext: ReactApplicationContext) :
11
12
  ActivityEventListener {
12
13
 
13
14
  companion object {
14
- const val WRAPPER_VERSION = "2.0.5"
15
+ const val WRAPPER_VERSION = "2.1.0"
15
16
  }
16
17
 
17
18
  private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
@@ -60,14 +61,71 @@ class ViaLinkModule(reactContext: ReactApplicationContext) :
60
61
  }
61
62
 
62
63
  @ReactMethod
63
- fun createLink(path: String, data: ReadableMap?, campaign: String?, promise: Promise) {
64
+ fun createLink(path: String, data: ReadableMap?, campaign: String?, linkType: String, promise: Promise) {
64
65
  scope.launch {
66
+ // linkType("dynamic" | "static") 을 native SDK에 전달.
67
+ // Android core SDK가 linkType 인자를 지원하면 아래 호출에 linkType을 함께 넘긴다.
65
68
  val result = ViaLinkSDK.createLink(path, data?.toHashMap()?.mapValues { it.value as Any }, campaign)
66
69
  result.onSuccess { promise.resolve(it) }
67
70
  result.onFailure { promise.reject("CREATE_LINK_ERROR", it.message) }
68
71
  }
69
72
  }
70
73
 
74
+ /// 결제 시도 이벤트를 native SDK(payment.initiated)로 전달.
75
+ /// args: { orderId, amount, currency, linkId?, paymentMethod?, metadata? }
76
+ /// resolve: { success: Boolean, paymentEventId: String }
77
+ @ReactMethod
78
+ fun paymentInitiated(args: ReadableMap, promise: Promise) {
79
+ try {
80
+ val orderId = if (args.hasKey("orderId") && !args.isNull("orderId"))
81
+ args.getString("orderId") else null
82
+ if (orderId.isNullOrEmpty()) {
83
+ return promise.reject("E_INVALID_ARG", "orderId가 필요합니다.")
84
+ }
85
+
86
+ if (!args.hasKey("amount") || args.isNull("amount")) {
87
+ return promise.reject("E_INVALID_ARG", "amount가 필요합니다.")
88
+ }
89
+ val amount = args.getDouble("amount")
90
+
91
+ val currency = if (args.hasKey("currency") && !args.isNull("currency"))
92
+ args.getString("currency") else null
93
+ if (currency.isNullOrEmpty()) {
94
+ return promise.reject("E_INVALID_ARG", "currency가 필요합니다.")
95
+ }
96
+
97
+ val linkId = if (args.hasKey("linkId") && !args.isNull("linkId"))
98
+ args.getInt("linkId") else null
99
+ val paymentMethod = if (args.hasKey("paymentMethod") && !args.isNull("paymentMethod"))
100
+ args.getString("paymentMethod") else null
101
+ val metadata = if (args.hasKey("metadata") && !args.isNull("metadata"))
102
+ args.getMap("metadata")?.toHashMap()?.mapValues { it.value as Any? } else null
103
+
104
+ val payArgs = PaymentInitiatedArgs(
105
+ orderId = orderId,
106
+ amount = amount,
107
+ currency = currency,
108
+ linkId = linkId,
109
+ paymentMethod = paymentMethod,
110
+ metadata = metadata,
111
+ )
112
+
113
+ scope.launch {
114
+ try {
115
+ val result = ViaLinkSDK.payment.initiated(payArgs)
116
+ val map = Arguments.createMap()
117
+ map.putBoolean("success", result.success)
118
+ map.putString("paymentEventId", result.paymentEventId)
119
+ promise.resolve(map)
120
+ } catch (e: Exception) {
121
+ promise.reject("E_PAYMENT_FAILED", e.message ?: e.toString(), e)
122
+ }
123
+ }
124
+ } catch (e: Exception) {
125
+ promise.reject("E_PAYMENT_FAILED", e.message ?: e.toString(), e)
126
+ }
127
+ }
128
+
71
129
  @ReactMethod
72
130
  fun addListener(eventName: String) {
73
131
  listenerCount++
@@ -3,6 +3,34 @@ export interface DeepLinkData {
3
3
  params: Record<string, string>;
4
4
  shortCode?: string;
5
5
  }
6
+ /**
7
+ * 결제 시도 이벤트 입력 인자.
8
+ *
9
+ * - orderId: 운영자가 발급하는 주문번호 (1~100자, 영문/숫자/하이픈/언더스코어)
10
+ * - amount: 결제 금액 (통화 단위 그대로, > 0)
11
+ * - currency: ISO 4217 통화 코드 (예: "KRW", "USD", "JPY")
12
+ * - linkId: (옵션) 사용자가 진입한 링크 id
13
+ * - paymentMethod: (옵션) 결제 수단 식별자 (예: "card", "kakao_pay")
14
+ * - metadata: (옵션) 운영자 자유 메타데이터 (iOS 호환을 위해 string-only)
15
+ */
16
+ export interface PaymentInitiatedArgs {
17
+ orderId: string;
18
+ amount: number;
19
+ currency: string;
20
+ linkId?: number;
21
+ paymentMethod?: string;
22
+ metadata?: Record<string, string>;
23
+ }
24
+ /**
25
+ * 결제 시도 응답.
26
+ *
27
+ * - success: 서버에서 성공 처리되었는지 여부
28
+ * - paymentEventId: 서버에서 발급한 결제 이벤트 ID (문자열로 정규화)
29
+ */
30
+ export interface PaymentInitiatedResult {
31
+ success: boolean;
32
+ paymentEventId: string;
33
+ }
6
34
  /**
7
35
  * ViaLink React Native SDK
8
36
  *
@@ -51,10 +79,39 @@ export declare class ViaLinkSDK {
51
79
  /**
52
80
  * 앱 내에서 딥링크 생성
53
81
  *
82
+ * - `dynamic` (기본값): 클릭할 때마다 통계·어트리뷰션이 집계되는 동적 링크
83
+ * - `static`: 고정된 목적지 URL만 제공하는 정적 링크 (통계 미집계)
84
+ *
54
85
  * ```typescript
86
+ * // 동적 링크 (기본값 — 생략 가능)
55
87
  * const url = await ViaLinkSDK.shared.createLink('/product/123', { promo: 'FRIEND' }, 'referral');
88
+ *
89
+ * // 정적 링크 (통계 미집계)
90
+ * const url = await ViaLinkSDK.shared.createLink('/product/123', { promo: 'FRIEND' }, 'referral', 'static');
91
+ * ```
92
+ */
93
+ createLink(path: string, data?: Record<string, unknown>, campaign?: string, linkType?: 'dynamic' | 'static'): Promise<string>;
94
+ /**
95
+ * 결제 추적 namespace.
96
+ *
97
+ * `succeeded`/`failed`는 서버-투-서버(S2S) 엔드포인트라 클라이언트 SDK에서는 노출하지 않습니다.
98
+ *
99
+ * ```typescript
100
+ * const result = await ViaLinkSDK.shared.payment.initiated({
101
+ * orderId: 'ORD-2026-0001',
102
+ * amount: 19900,
103
+ * currency: 'KRW',
104
+ * paymentMethod: 'card',
105
+ * });
106
+ * // result.success === true, result.paymentEventId === '123'
56
107
  * ```
57
108
  */
58
- createLink(path: string, data?: Record<string, unknown>, campaign?: string): Promise<string>;
109
+ readonly payment: {
110
+ /**
111
+ * 결제 시도 기록 (POST /v1/payments/initiated).
112
+ * 결제창을 띄우기 직전에 호출합니다. 즉시 전송 (배치 X).
113
+ */
114
+ initiated: (args: PaymentInitiatedArgs) => Promise<PaymentInitiatedResult>;
115
+ };
59
116
  destroy(): void;
60
117
  }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { ViaLinkSDK } from './ViaLinkSDK';
2
- export type { DeepLinkData } from './ViaLinkSDK';
2
+ export type { DeepLinkData, PaymentInitiatedArgs, PaymentInitiatedResult, } from './ViaLinkSDK';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var reactNative=require('react-native');var {ViaLinkSDK:i}=reactNative.NativeModules,r=new reactNative.NativeEventEmitter(i),n=class a{constructor(){}static get shared(){return this._instance||(this._instance=new a),this._instance}async configure(e){await i.configure(e);}onDeepLink(e){this.deepLinkSub?.remove(),this.deepLinkSub=r.addListener("onDeepLink",e);}onDeferredDeepLink(e){this.deferredSub?.remove(),this.deferredSub=r.addListener("onDeferredDeepLink",e);}track(e,t){i.track(e,t??null);}async createLink(e,t,s){return i.createLink(e,t??null,s??null)}destroy(){this.deepLinkSub?.remove(),this.deferredSub?.remove();}};exports.ViaLinkSDK=n;
1
+ 'use strict';var reactNative=require('react-native');var {ViaLinkSDK:n}=reactNative.NativeModules,i=new reactNative.NativeEventEmitter(n),m=/^[A-Za-z0-9_-]{1,100}$/,r=class a{constructor(){this.payment={initiated:async e=>{if(!e||typeof e!="object")throw new Error("args\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");if(typeof e.orderId!="string"||!m.test(e.orderId))throw new Error("order_id \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (1~100\uC790, \uC601\uBB38/\uC22B\uC790/\uD558\uC774\uD508/\uC5B8\uB354\uC2A4\uCF54\uC5B4).");if(typeof e.amount!="number"||!Number.isFinite(e.amount)||e.amount<=0)throw new Error("amount\uB294 0\uBCF4\uB2E4 \uD070 \uC22B\uC790\uC5EC\uC57C \uD569\uB2C8\uB2E4.");if(typeof e.currency!="string"||e.currency.trim().length===0)throw new Error("currency\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");let t=await n.paymentInitiated({orderId:e.orderId,amount:e.amount,currency:e.currency.trim().toUpperCase(),linkId:e.linkId??null,paymentMethod:e.paymentMethod??null,metadata:e.metadata??null});return {success:!!t?.success,paymentEventId:String(t?.paymentEventId??"")}}};}static get shared(){return this._instance||(this._instance=new a),this._instance}async configure(e){await n.configure(e);}onDeepLink(e){this.deepLinkSub?.remove(),this.deepLinkSub=i.addListener("onDeepLink",e);}onDeferredDeepLink(e){this.deferredSub?.remove(),this.deferredSub=i.addListener("onDeferredDeepLink",e);}track(e,t){n.track(e,t??null);}async createLink(e,t,o,d="dynamic"){return n.createLink(e,t??null,o??null,d)}destroy(){this.deepLinkSub?.remove(),this.deferredSub?.remove();}};exports.ViaLinkSDK=r;
@@ -8,32 +8,32 @@
8
8
  <key>BinaryPath</key>
9
9
  <string>ViaLinkCore.framework/ViaLinkCore</string>
10
10
  <key>LibraryIdentifier</key>
11
- <string>ios-arm64</string>
11
+ <string>ios-arm64_x86_64-simulator</string>
12
12
  <key>LibraryPath</key>
13
13
  <string>ViaLinkCore.framework</string>
14
14
  <key>SupportedArchitectures</key>
15
15
  <array>
16
16
  <string>arm64</string>
17
+ <string>x86_64</string>
17
18
  </array>
18
19
  <key>SupportedPlatform</key>
19
20
  <string>ios</string>
21
+ <key>SupportedPlatformVariant</key>
22
+ <string>simulator</string>
20
23
  </dict>
21
24
  <dict>
22
25
  <key>BinaryPath</key>
23
26
  <string>ViaLinkCore.framework/ViaLinkCore</string>
24
27
  <key>LibraryIdentifier</key>
25
- <string>ios-arm64_x86_64-simulator</string>
28
+ <string>ios-arm64</string>
26
29
  <key>LibraryPath</key>
27
30
  <string>ViaLinkCore.framework</string>
28
31
  <key>SupportedArchitectures</key>
29
32
  <array>
30
33
  <string>arm64</string>
31
- <string>x86_64</string>
32
34
  </array>
33
35
  <key>SupportedPlatform</key>
34
36
  <string>ios</string>
35
- <key>SupportedPlatformVariant</key>
36
- <string>simulator</string>
37
37
  </dict>
38
38
  </array>
39
39
  <key>CFBundlePackageType</key>
@@ -13,6 +13,11 @@ RCT_EXTERN_METHOD(track:(NSString *)eventName
13
13
  RCT_EXTERN_METHOD(createLink:(NSString *)path
14
14
  data:(NSDictionary *)data
15
15
  campaign:(NSString *)campaign
16
+ linkType:(NSString *)linkType
17
+ resolve:(RCTPromiseResolveBlock)resolve
18
+ reject:(RCTPromiseRejectBlock)reject)
19
+
20
+ RCT_EXTERN_METHOD(paymentInitiated:(NSDictionary *)args
16
21
  resolve:(RCTPromiseResolveBlock)resolve
17
22
  reject:(RCTPromiseRejectBlock)reject)
18
23
 
@@ -1,11 +1,11 @@
1
1
  import Foundation
2
2
  import React
3
- import ViaLinkSDK // xcframework
3
+ import ViaLinkCore // xcframework module: ViaLinkCore (class: ViaLinkSDK)
4
4
 
5
5
  @objc(ViaLinkSDK)
6
6
  class ViaLinkModule: RCTEventEmitter {
7
7
 
8
- static let wrapperVersion = "2.0.5"
8
+ static let wrapperVersion = "2.1.0"
9
9
 
10
10
  private var pendingDeepLink: [String: Any?]?
11
11
  private var pendingDeferred: [String: Any?]?
@@ -65,10 +65,13 @@ class ViaLinkModule: RCTEventEmitter {
65
65
  }
66
66
 
67
67
  @objc func createLink(_ path: String, data: NSDictionary?, campaign: String?,
68
+ linkType: String,
68
69
  resolve: @escaping RCTPromiseResolveBlock,
69
70
  reject: @escaping RCTPromiseRejectBlock) {
70
71
  Task {
71
72
  do {
73
+ // TODO: ViaLinkCore가 linkType을 지원하면 아래 호출에 linkType 전달 필요.
74
+ // 현재 iOS core SDK는 다른 sub-agent가 linkType 인자를 추가 중.
72
75
  let url = try await ViaLinkSDK.shared.createLink(path: path, data: data as? [String: Any], campaign: campaign)
73
76
  DispatchQueue.main.async { resolve(url) }
74
77
  } catch {
@@ -76,6 +79,55 @@ class ViaLinkModule: RCTEventEmitter {
76
79
  }
77
80
  }
78
81
  }
82
+
83
+ /// 결제 시도 이벤트를 native iOS SDK(ViaLinkSDK.shared.payment.initiated)로 전달.
84
+ /// args: { orderId, amount, currency, linkId?, paymentMethod?, metadata? }
85
+ /// resolve: { success: Bool, paymentEventId: String }
86
+ @objc func paymentInitiated(_ args: NSDictionary,
87
+ resolve: @escaping RCTPromiseResolveBlock,
88
+ reject: @escaping RCTPromiseRejectBlock) {
89
+ guard let orderId = args["orderId"] as? String, !orderId.isEmpty else {
90
+ reject("E_INVALID_ARG", "orderId가 필요합니다.", nil)
91
+ return
92
+ }
93
+ guard let amountValue = args["amount"] as? NSNumber else {
94
+ reject("E_INVALID_ARG", "amount가 필요합니다.", nil)
95
+ return
96
+ }
97
+ guard let currency = args["currency"] as? String, !currency.isEmpty else {
98
+ reject("E_INVALID_ARG", "currency가 필요합니다.", nil)
99
+ return
100
+ }
101
+
102
+ let linkId = args["linkId"] as? Int
103
+ let paymentMethod = args["paymentMethod"] as? String
104
+ let metadata = args["metadata"] as? [String: String]
105
+
106
+ let payArgs = PaymentInitiatedArgs(
107
+ orderId: orderId,
108
+ amount: amountValue.doubleValue,
109
+ currency: currency,
110
+ linkId: linkId,
111
+ paymentMethod: paymentMethod,
112
+ metadata: metadata
113
+ )
114
+
115
+ Task {
116
+ do {
117
+ let result = try await ViaLinkSDK.shared.payment.initiated(payArgs)
118
+ DispatchQueue.main.async {
119
+ resolve([
120
+ "success": result.success,
121
+ "paymentEventId": result.paymentEventId,
122
+ ])
123
+ }
124
+ } catch {
125
+ DispatchQueue.main.async {
126
+ reject("E_PAYMENT_FAILED", error.localizedDescription, error)
127
+ }
128
+ }
129
+ }
130
+ }
79
131
  }
80
132
 
81
133
  extension DeepLinkData {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vialink-react-native-sdk",
3
- "version": "2.0.15",
3
+ "version": "2.1.1",
4
4
  "description": "ViaLink 딥링크 SDK for React Native (네이티브 브릿지)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  Pod::Spec.new do |s|
2
2
  s.name = "vialink-react-native-sdk"
3
- s.version = "2.0.15"
3
+ s.version = "2.1.1"
4
4
  s.summary = "ViaLink Deep Link SDK for React Native"
5
5
  s.homepage = "https://vialink.app"
6
6
  s.license = "MIT"