vialink-react-native-sdk 2.1.10 → 3.0.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.
@@ -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.DeferredError
7
8
  import com.vialink.sdk.model.PaymentInitiatedArgs
8
9
  import kotlinx.coroutines.*
9
10
 
@@ -44,10 +45,14 @@ class ViaLinkModule(reactContext: ReactApplicationContext) :
44
45
  if (listenerCount > 0) sendEvent("onDeepLink", map)
45
46
  else pendingDeepLink = map
46
47
  }
47
- ViaLinkSDK.onDeferredDeepLink { data ->
48
- val map = data.toWritableMap()
49
- if (listenerCount > 0) sendEvent("onDeferredDeepLink", map)
50
- else pendingDeferred = map
48
+ // 디퍼드 콜백: SDK 3.0+ 시그니처 (data, error) — 항상 1회 호출
49
+ // JS emit 페이로드는 `{data, error}` 객체로 전달한다.
50
+ ViaLinkSDK.onDeferredDeepLink { data, error ->
51
+ val payload = Arguments.createMap()
52
+ data?.let { payload.putMap("data", it.toWritableMap()) }
53
+ error?.let { payload.putMap("error", it.toWritableMap()) }
54
+ if (listenerCount > 0) sendEvent("onDeferredDeepLink", payload)
55
+ else pendingDeferred = payload
51
56
  }
52
57
 
53
58
  currentActivity?.intent?.let { ViaLinkSDK.handleIntent(it) }
@@ -201,3 +206,13 @@ private fun DeepLinkData.toWritableMap(): WritableMap {
201
206
  linkId?.let { map.putInt("linkId", it) }
202
207
  return map
203
208
  }
209
+
210
+ // DeferredError → WritableMap (JS DeferredError 인터페이스와 키가 일치해야 함)
211
+ private fun DeferredError.toWritableMap(): WritableMap {
212
+ val map = Arguments.createMap()
213
+ map.putString("code", code)
214
+ map.putString("message", message)
215
+ httpStatus?.let { map.putInt("httpStatus", it) }
216
+ map.putBoolean("retryable", retryable)
217
+ return map
218
+ }
@@ -4,6 +4,26 @@ export interface DeepLinkData {
4
4
  shortCode?: string;
5
5
  linkId?: number;
6
6
  }
7
+ /**
8
+ * 디퍼드 매칭 실패 정보
9
+ *
10
+ * `onDeferredDeepLink((data, error) => ...)` 콜백의 두 번째 인자로 전달된다.
11
+ * `data == null && error == null`이면 매칭 결과가 "없음"(organic install)이다.
12
+ *
13
+ * - `code`:
14
+ * - `'timeout'`: 5초 데드라인 만료
15
+ * - `'network'`: DNS 실패, 연결 거부 등 (3회 재시도 모두 실패)
16
+ * - `'server_error'`: HTTP 5xx (3회 재시도 모두 실패)
17
+ * - `'invalid_response'`: 응답 JSON 파싱 실패
18
+ * - `'unknown'`: 그 외 모든 예외
19
+ * - `retryable`이 true면 SDK가 다음 앱 실행에서 자동으로 다시 시도한다.
20
+ */
21
+ export interface DeferredError {
22
+ code: 'timeout' | 'network' | 'server_error' | 'invalid_response' | 'unknown';
23
+ message: string;
24
+ httpStatus?: number;
25
+ retryable: boolean;
26
+ }
7
27
  /**
8
28
  * 결제 시도 이벤트 입력 인자.
9
29
  *
@@ -78,9 +98,28 @@ export declare class ViaLinkSDK {
78
98
  onDeepLink(callback: (data: DeepLinkData) => void): void;
79
99
  /**
80
100
  * 디퍼드 딥링크 콜백 등록
81
- * 앱 첫 설치 후 실행 시 fingerprint 매칭으로 딥링크 데이터를 전달합니다.
101
+ *
102
+ * 앱 첫 실행 시 매칭 결과가 결정되는 즉시 항상 1회 호출됩니다.
103
+ * 5초 안에 결과가 결정되지 않으면 `error.code === 'timeout'`으로 호출됩니다.
104
+ *
105
+ * ```typescript
106
+ * ViaLinkSDK.shared.onDeferredDeepLink((data, error) => {
107
+ * if (error) {
108
+ * // 매칭 실패 (timeout/network/server_error 등) — 일반 진입
109
+ * return;
110
+ * }
111
+ * if (!data) {
112
+ * // organic install — 일반 진입
113
+ * return;
114
+ * }
115
+ * navigation.navigate(data.path, data.params);
116
+ * });
117
+ * ```
118
+ *
119
+ * 콜백은 멱등성을 보장합니다 (총 1회 호출).
120
+ * `error.retryable`이 true면 다음 앱 실행에서 자동 재시도되며, 그 경우 사용자가 앱을 사용 중일 때 콜백이 도착할 수 있습니다.
82
121
  */
83
- onDeferredDeepLink(callback: (data: DeepLinkData) => void): void;
122
+ onDeferredDeepLink(callback: (data: DeepLinkData | null, error: DeferredError | null) => void): void;
84
123
  /**
85
124
  * 커스텀 이벤트 추적
86
125
  *
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { ViaLinkSDK } from './ViaLinkSDK';
2
- export type { DeepLinkData, PaymentInitiatedArgs, PaymentInitiatedResult, } from './ViaLinkSDK';
2
+ export type { DeepLinkData, DeferredError, PaymentInitiatedArgs, PaymentInitiatedResult, } from './ViaLinkSDK';
package/dist/index.js CHANGED
@@ -1 +1 @@
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,s="static",d){return n.createLink(e,t??null,o??null,s,d??null)}destroy(){this.deepLinkSub?.remove(),this.deferredSub?.remove();}};exports.ViaLinkSDK=r;
1
+ 'use strict';var reactNative=require('react-native');var {ViaLinkSDK:r}=reactNative.NativeModules,i=new reactNative.NativeEventEmitter(r),l=/^[A-Za-z0-9_-]{1,100}$/,n=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"||!l.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 r.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 r.configure(e);}onDeepLink(e){this.deepLinkSub?.remove(),this.deepLinkSub=i.addListener("onDeepLink",e);}onDeferredDeepLink(e){this.deferredSub?.remove(),this.deferredSub=i.addListener("onDeferredDeepLink",t=>{e(t?.data??null,t?.error??null);});}track(e,t){r.track(e,t??null);}async createLink(e,t,o,s="static",d){return r.createLink(e,t??null,o??null,s,d??null)}destroy(){this.deepLinkSub?.remove(),this.deferredSub?.remove();}};exports.ViaLinkSDK=n;
@@ -46,12 +46,16 @@ class ViaLinkModule: RCTEventEmitter {
46
46
  }
47
47
  }
48
48
 
49
- ViaLinkSDK.shared.onDeferredDeepLink { [weak self] data in
50
- let map = data.toDictionary()
49
+ // 디퍼드 콜백: SDK 3.0+ 시그니처 (data, error) — 항상 1회 호출
50
+ // JS emit 페이로드는 `{data, error}` 객체로 전달한다.
51
+ ViaLinkSDK.shared.onDeferredDeepLink { [weak self] data, error in
52
+ var payload: [String: Any?] = [:]
53
+ if let data = data { payload["data"] = data.toDictionary() }
54
+ if let error = error { payload["error"] = error.toDictionary() }
51
55
  if self?.hasListeners == true {
52
- self?.sendEvent(withName: "onDeferredDeepLink", body: map)
56
+ self?.sendEvent(withName: "onDeferredDeepLink", body: payload)
53
57
  } else {
54
- self?.pendingDeferred = map
58
+ self?.pendingDeferred = payload
55
59
  }
56
60
  }
57
61
 
@@ -151,3 +155,15 @@ extension DeepLinkData {
151
155
  ["path": path, "params": params, "shortCode": shortCode, "linkId": linkId]
152
156
  }
153
157
  }
158
+
159
+ extension DeferredError {
160
+ /// JS DeferredError 인터페이스와 키가 일치해야 함
161
+ func toDictionary() -> [String: Any?] {
162
+ [
163
+ "code": code.rawValue,
164
+ "message": message,
165
+ "httpStatus": httpStatus,
166
+ "retryable": retryable,
167
+ ]
168
+ }
169
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vialink-react-native-sdk",
3
- "version": "2.1.10",
3
+ "version": "3.0.0",
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.1.10"
3
+ s.version = "3.0.0"
4
4
  s.summary = "ViaLink Deep Link SDK for React Native"
5
5
  s.homepage = "https://vialink.app"
6
6
  s.license = "MIT"