@retion-miniapp/sdk 0.7.2 → 0.8.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.
- package/CHANGELOG.md +19 -0
- package/README.md +65 -8
- package/dist/index.cjs +9 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -6
- package/dist/index.d.ts +45 -6
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.1 — 2026-10-28
|
|
4
|
+
|
|
5
|
+
### Docs
|
|
6
|
+
- Phát hành README tiếng Việt đầy đủ cho biometric và speech-to-text: setup app chủ, API, response, event, lỗi và vòng đời phiên. Thêm các API mới vào bảng mục lục và liên kết gist hướng dẫn.
|
|
7
|
+
- Khuyên dùng Mini App React Native 0.8.1 để có bản sửa listener speech. Không thay đổi API so với Web SDK 0.8.0.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## 0.8.0 — 2026-10-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Speech-to-text qua bridge Mini App chung: bắt đầu/dừng, event tạm thời/cuối cùng/lỗi/kết thúc. Native tự xin quyền và quản lý phiên micro, huỷ khi mini app đóng/ẩn hoặc app xuống nền.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## 0.7.3 — 2026-10-28
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- Trả nguyên kết quả sinh trắc học từ native, gồm `success: false` và `error`; không tự chuyển kết quả huỷ thành lỗi. Phía gọi cần kiểm tra `result.success`.
|
|
20
|
+
|
|
21
|
+
|
|
3
22
|
Định dạng theo [Keep a Changelog](https://keepachangelog.com/vi/1.1.0/), version theo [SemVer](https://semver.org/).
|
|
4
23
|
|
|
5
24
|
## Unreleased
|
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
SDK cho web mini app chạy trong app Retion.
|
|
4
4
|
|
|
5
|
+
Tài liệu **Web SDK 0.8.1**, dùng với **Mini App React Native 0.8.1** để có đầy đủ Face ID / Touch ID và speech-to-text đã sửa listener native. App chủ tự cấu hình quyền và build native một lần; web chỉ gọi API và nhận kết quả/event.
|
|
6
|
+
|
|
7
|
+
[Hướng dẫn tích hợp app chủ](https://gist.github.com/vanqui123/e90b4efc40b8a85cc7a4b922ef0378b8) · [Face ID / Touch ID](#face-id--touch-id--android-biometrics) · [Speech-to-text](#nhận-dạng-giọng-nói-080)
|
|
8
|
+
|
|
5
9
|
```bash
|
|
6
10
|
npm i @retion-miniapp/sdk
|
|
7
11
|
```
|
|
@@ -19,6 +23,8 @@ npm i @retion-miniapp/sdk
|
|
|
19
23
|
| [`openScreen({ screen, params })`](#openscreen-screen-params-) | Mở 1 màn hình của app |
|
|
20
24
|
| [`openLink(url)`](#openlinkurl) | Mở link bằng hệ điều hành (deeplink app khác, tel:, mailto:, https) |
|
|
21
25
|
| [`haptic(type)`](#haptictype) | Rung phản hồi (bấm nút, thanh toán xong…) |
|
|
26
|
+
| [`getBiometricAvailability()` / `authenticateBiometric(req)`](#face-id--touch-id--android-biometrics) | Kiểm tra Face ID / Touch ID và trả nguyên kết quả xác thực native |
|
|
27
|
+
| [`startSpeech(options)` / `stopSpeech()` / `onSpeech(event, cb)`](#nhận-dạng-giọng-nói-080) | Bắt đầu/dừng nhận dạng và nhận văn bản tạm thời/cuối cùng |
|
|
22
28
|
|
|
23
29
|
**1 mini app = 1 trang, load 1 lần.** Mở mini app ở page / conversation khác, app **không nạp lại trang** mà gọi `onContextChange` — thiếu nó web sẽ hiện dữ liệu page cũ. Đổi tổ chức thì app nạp lại trang.
|
|
24
30
|
|
|
@@ -308,20 +314,71 @@ MIT
|
|
|
308
314
|
|
|
309
315
|
### Face ID / Touch ID / Android biometrics
|
|
310
316
|
|
|
311
|
-
|
|
317
|
+
Với Web SDK **0.8.1**, app chủ cài `@retion-miniapp/react-native@0.8.1` và hoàn tất cấu hình quyền/native. Package tự xử lý biometric, không cần truyền adapter. Xem [cấu hình app chủ](https://github.com/vanqui123/retion-miniapp-react-native/blob/main/docs/BIOMETRICS.md).
|
|
312
318
|
|
|
313
319
|
```ts
|
|
314
320
|
import { getBiometricAvailability, authenticateBiometric } from '@retion-miniapp/sdk';
|
|
315
321
|
|
|
316
322
|
const { available, biometryType } = await getBiometricAvailability();
|
|
317
323
|
if (available) {
|
|
318
|
-
await authenticateBiometric({ reason: 'Xác nhận danh tính', cancelButtonText: 'Huỷ' });
|
|
324
|
+
const result = await authenticateBiometric({ reason: 'Xác nhận danh tính', cancelButtonText: 'Huỷ' });
|
|
325
|
+
if (!result.success) console.log(result.error);
|
|
319
326
|
}
|
|
320
327
|
```
|
|
321
328
|
|
|
322
|
-
|
|
323
|
-
`
|
|
324
|
-
`
|
|
325
|
-
|
|
326
|
-
`
|
|
327
|
-
|
|
329
|
+
Từ Web SDK **0.7.3** và host **0.7.8**, kết quả được giữ nguyên từ thư viện native:
|
|
330
|
+
`{ success: boolean, error?: string }`. Người dùng huỷ có thể trả `success: false`; hãy kiểm tra
|
|
331
|
+
`result.success` trước khi tiếp tục. Lỗi native bị reject vẫn đi qua `MiniAppError` của bridge,
|
|
332
|
+
giữ mã và thông báo do native cung cấp khi có. Lỗi bridge như `BUSY`, `INVALID_PARAMS`,
|
|
333
|
+
`NOT_SUPPORTED`, `NOT_IN_HOST`, `TIMEOUT` vẫn được reject.
|
|
334
|
+
`getBiometricAvailability()` giữ nguyên cả trường `error` của native nếu có.
|
|
335
|
+
API xác minh trên thiết bị, không trả dữ liệu sinh trắc học hoặc token đăng nhập backend.
|
|
336
|
+
|
|
337
|
+
### Nhận dạng giọng nói (0.8.0)
|
|
338
|
+
|
|
339
|
+
API speech có từ **0.8.0**. Khuyên dùng Web SDK **0.8.1** và Mini App React Native **0.8.1**, gồm bản sửa đăng ký listener trên đúng native module để nhận text và event kết thúc. App chủ cấu hình Expo Modules, quyền micro/nhận dạng và build native một lần. Không gắn handler speech hay gửi message theo kênh `chat_sdk`. Xem [hướng dẫn cài đặt và hoạt động đầy đủ](https://github.com/vanqui123/retion-miniapp-react-native/blob/main/docs/SPEECH.md).
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
import { startSpeech, stopSpeech, onSpeech } from '@retion-miniapp/sdk';
|
|
343
|
+
|
|
344
|
+
// Đăng ký một lần khi component được tạo, trước khi bắt đầu nghe.
|
|
345
|
+
const offPartial = onSpeech('speech.partial', result => console.log(result.text));
|
|
346
|
+
const offFinal = onSpeech('speech.final', result => console.log(result.text, result.results));
|
|
347
|
+
const offError = onSpeech('speech.error', error => console.error(error.code, error.message));
|
|
348
|
+
const offEnd = onSpeech('speech.end', () => console.log('Phiên nghe đã kết thúc'));
|
|
349
|
+
|
|
350
|
+
// Nút bắt đầu gọi hàm này. Promise không trả văn bản.
|
|
351
|
+
async function startListening() {
|
|
352
|
+
try { await startSpeech({ lang: 'vi-VN' }); }
|
|
353
|
+
catch (error) { console.error('Không bắt đầu được:', error); }
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Nút dừng: vẫn chờ kết quả cuối hoặc lỗi và event speech.end.
|
|
357
|
+
async function stopListening() {
|
|
358
|
+
try { await stopSpeech(); }
|
|
359
|
+
catch (error) { console.error('Không dừng được:', error); }
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Khi rời màn hình trong web: dừng nếu không còn cần nghe, rồi dọn listener.
|
|
363
|
+
// Nếu cần lưu câu cuối, giữ listener cho đến speech.end trước khi dọn.
|
|
364
|
+
async function dispose() {
|
|
365
|
+
try { await stopSpeech(); }
|
|
366
|
+
finally { offPartial(); offFinal(); offError(); offEnd(); }
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
| API / event | Kết quả |
|
|
371
|
+
| --- | --- |
|
|
372
|
+
| `startSpeech(options?)` | `Promise<void>` sau khi xin quyền và gửi lệnh bắt đầu; chờ tối đa 2 phút |
|
|
373
|
+
| `stopSpeech()` | `Promise<void>` khi gửi lệnh dừng; chờ phản hồi bridge tối đa 15 giây, không phải chờ câu cuối |
|
|
374
|
+
| `speech.partial` / `speech.final` | `{ text, isFinal, results, ... }`; giữ dữ liệu native và thêm `text` |
|
|
375
|
+
| `speech.error` | `{ code, error, message, ... }`; lỗi xảy ra trong phiên |
|
|
376
|
+
| `speech.end` | `undefined`; native kết thúc và host đã giải phóng phiên |
|
|
377
|
+
|
|
378
|
+
Mặc định: `lang: 'vi-VN'`, `continuous: true`, `interimResults: true`, `addsPunctuation: true`, `requiresOnDeviceRecognition: false`. Web có thể truyền các tuỳ chọn này vào `startSpeech`; tính năng nhận dạng tuỳ thuộc dịch vụ và ngôn ngữ trên thiết bị.
|
|
379
|
+
|
|
380
|
+
Chỉ một mini app được giữ phiên. Phiên đang bận trả `BUSY`; thiếu quyền trả `PERMISSION_DENIED`; tham số sai trả `INVALID_PARAMS`; mini app không còn hoạt động trả `CANCELLED`; thiếu native module trả `NOT_SUPPORTED`. Lỗi khởi động đi vào Promise; lỗi nhận dạng đi qua event. Host cũ có thể không hỗ trợ API. Trình duyệt ngoài host trả `NOT_IN_HOST`.
|
|
381
|
+
|
|
382
|
+
Dừng không đảm bảo luôn có `speech.final`: native có thể không nhận được lời nói hoặc báo lỗi rồi kết thúc. `speech.final` trong chế độ nghe liên tục cũng không có nghĩa phiên đã kết thúc. Chỉ dựa vào `speech.end` để biết phiên đã được giải phóng.
|
|
383
|
+
|
|
384
|
+
Đóng/ẩn mini app, reload WebView hoặc app xuống nền sẽ huỷ phiên. Huỷ listener web không tự tắt micro. Hết thời gian chờ web không tự huỷ lời gọi native hoặc đóng hộp xin quyền; nếu không còn muốn nghe, yêu cầu dừng. API speech không phụ thuộc cài đặt ngôn ngữ của Chat SDK.
|
package/dist/index.cjs
CHANGED
|
@@ -157,7 +157,7 @@ var on = (event, listener) => {
|
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
// src/version.ts
|
|
160
|
-
var SDK_VERSION = "0.
|
|
160
|
+
var SDK_VERSION = "0.8.1" ;
|
|
161
161
|
|
|
162
162
|
// src/apis/app.ts
|
|
163
163
|
var closeApp = () => call("closeApp");
|
|
@@ -232,6 +232,11 @@ var haptic = (type = HapticType.selection) => notify("haptic", { type });
|
|
|
232
232
|
var getBiometricAvailability = () => call("getBiometricAvailability");
|
|
233
233
|
var authenticateBiometric = (request) => call("authenticateBiometric", request, 10 * 60 * 1e3);
|
|
234
234
|
|
|
235
|
+
// src/apis/speech.ts
|
|
236
|
+
var startSpeech = (options = {}) => call("speech.start", options, 12e4);
|
|
237
|
+
var stopSpeech = () => call("speech.stop");
|
|
238
|
+
var onSpeech = (event, listener) => on(event, (data) => listener(data));
|
|
239
|
+
|
|
235
240
|
// src/index.ts
|
|
236
241
|
if (typeof window !== "undefined") {
|
|
237
242
|
getState();
|
|
@@ -257,9 +262,12 @@ exports.isInHost = isInHost;
|
|
|
257
262
|
exports.onAppPaused = onAppPaused;
|
|
258
263
|
exports.onAppResumed = onAppResumed;
|
|
259
264
|
exports.onContextChange = onContextChange;
|
|
265
|
+
exports.onSpeech = onSpeech;
|
|
260
266
|
exports.openLink = openLink;
|
|
261
267
|
exports.openScreen = openScreen;
|
|
262
268
|
exports.printImage = printImage;
|
|
263
269
|
exports.requestPayment = requestPayment;
|
|
270
|
+
exports.startSpeech = startSpeech;
|
|
271
|
+
exports.stopSpeech = stopSpeech;
|
|
264
272
|
//# sourceMappingURL=index.cjs.map
|
|
265
273
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/bridge.ts","../src/version.ts","../src/apis/app.ts","../src/apis/route.ts","../src/apis/user.ts","../src/apis/native.ts","../src/apis/biometrics.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export const ErrorCode = {\n INVALID_PARAMS: 'INVALID_PARAMS',\n BIOMETRIC_UNAVAILABLE: 'BIOMETRIC_UNAVAILABLE',\n AUTHENTICATION_FAILED: 'AUTHENTICATION_FAILED',\n /** Không chạy trong app Retion (trình duyệt / iframe cũ). */\n NOT_IN_HOST: 'NOT_IN_HOST',\n /** Host không phản hồi trong thời gian chờ. */\n TIMEOUT: 'TIMEOUT',\n /** Mini app chưa được admin cấp quyền (vd lấy partner_token / chatbox_token). */\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n /** Host (phiên bản app hiện tại) chưa hỗ trợ API này. */\n NOT_SUPPORTED: 'NOT_SUPPORTED',\n /** Người dùng huỷ thao tác (đóng màn thanh toán, không chọn máy in…). */\n CANCELLED: 'CANCELLED',\n /** Đang có 1 lượt cùng loại chạy (vd đang thanh toán mà gọi requestPayment lần nữa). */\n BUSY: 'BUSY',\n /** Lỗi khác phía host. */\n HOST_ERROR: 'HOST_ERROR',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode] | (string & {});\n\nexport class MiniAppError extends Error {\n readonly code: ErrorCode;\n readonly method?: string;\n\n constructor(code: ErrorCode, message: string, method?: string) {\n super(message);\n this.name = 'MiniAppError';\n this.code = code;\n this.method = method;\n }\n\n /** Chuẩn hoá lỗi từ host (object thuần, Error, string) về MiniAppError. */\n static from(error: unknown, method?: string): MiniAppError {\n if (error instanceof MiniAppError) {\n return error;\n }\n if (error && typeof error === 'object') {\n const { code, message } = error as { code?: unknown; message?: unknown };\n return new MiniAppError(\n typeof code === 'string' ? code : ErrorCode.HOST_ERROR,\n typeof message === 'string' ? message : 'Unknown error',\n method,\n );\n }\n return new MiniAppError(ErrorCode.HOST_ERROR, String(error), method);\n }\n}\n","/**\n * Bridge web mini app ↔ host (app Retion). Nội bộ SDK — dev mini app không import trực tiếp.\n *\n * Giao thức v1\n * web → host : ReactNativeWebView.postMessage(JSON.stringify(RequestMessage))\n * host → web : window.__RETION_MINIAPP__.receive(ResponseMessage | EventMessage)\n * host → web event \"context\" → web gọi onContextChange → web → host \"contextApplied\"\n * host inject trước khi trang chạy:\n * window.__RETION_MINIAPP_HOST__ = { protocol } ← đánh dấu host hỗ trợ SDK\n * window.__RETION_MINIAPP_CONTEXT__ = RouteParams ← context ban đầu\n *\n * Chỉ có ReactNativeWebView KHÔNG đủ để coi là host: màn iframe cũ của app cũng là RN WebView\n * nhưng không hiểu giao thức này (gọi API sẽ treo tới timeout). Thiếu marker → NOT_IN_HOST ngay.\n *\n * State đặt trên window (singleton): nhiều bản SDK trong cùng trang (trùng version trong\n * node_modules) vẫn dùng chung 1 bridge thay vì ghi đè hàm receive của nhau.\n */\nimport { ErrorCode, MiniAppError } from './errors';\nimport type { RouteParams } from './types';\n\nexport const PROTOCOL_VERSION = 1;\nexport const DEFAULT_TIMEOUT_MS = 15_000;\nexport const CONTEXT_EVENT = 'context';\n/** web → host: đã áp dụng context mới (sau khi gọi các listener onContextChange). */\nexport const CONTEXT_APPLIED = 'contextApplied';\n\nexport interface RequestMessage {\n __retion: typeof PROTOCOL_VERSION;\n /** Có id → host phải trả ResponseMessage. Không có → lệnh 1 chiều. */\n id?: string;\n method: string;\n params?: unknown;\n}\n\nexport type ResponseMessage =\n | { id: string; result?: unknown; error?: undefined }\n | { id: string; error: { code: string; message: string } };\n\nexport interface EventMessage {\n event: string;\n data?: unknown;\n}\n\nexport interface HostInfo {\n /** Phiên bản giao thức host hỗ trợ. */\n protocol: number;\n}\n\ntype Listener = (data: unknown) => void;\n\ninterface Pending {\n method: string;\n resolve: (value: unknown) => void;\n reject: (error: MiniAppError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface BridgeState {\n protocol: number;\n seq: number;\n pending: Map<string, Pending>;\n listeners: Map<string, Set<Listener>>;\n context: RouteParams;\n receive: (message: ResponseMessage | EventMessage) => void;\n}\n\ndeclare global {\n interface Window {\n ReactNativeWebView?: { postMessage: (message: string) => void };\n __RETION_MINIAPP__?: BridgeState;\n __RETION_MINIAPP_CONTEXT__?: RouteParams;\n __RETION_MINIAPP_HOST__?: HostInfo;\n }\n}\n\nconst hasWindow = typeof window !== 'undefined';\n\nconst readInitialContext = (): RouteParams => {\n if (!hasWindow) {\n return {};\n }\n const query = Object.fromEntries(new URLSearchParams(window.location.search));\n return { ...query, ...(window.__RETION_MINIAPP_CONTEXT__ ?? {}) };\n};\n\nconst createState = (): BridgeState => {\n const state: BridgeState = {\n protocol: PROTOCOL_VERSION,\n seq: 0,\n pending: new Map(),\n listeners: new Map(),\n context: readInitialContext(),\n receive: (message) => {\n if (!message || typeof message !== 'object') {\n return;\n }\n if ('event' in message) {\n if (message.event === CONTEXT_EVENT) {\n // Cập nhật context TRƯỚC khi emit → getRouteParams() luôn đúng, kể cả không ai lắng nghe.\n const prev = state.context;\n // Host luôn gửi ĐỦ context của lần mở → thay hẳn, không gộp với context cũ: gộp thì param\n // lần trước không còn (vd. message_id khi mở từ nút CTA rồi mở lại từ menu) vẫn bị giữ lại.\n const next = { ...(message.data as RouteParams) };\n // Host đẩy lại context lúc \"ready\" dù không đổi → không báo onContextChange thừa.\n if (JSON.stringify(next) !== JSON.stringify(prev)) {\n state.context = next;\n emit(state, CONTEXT_EVENT, { next: { ...next }, prev });\n }\n // Báo host: web đã nhận context (listener đã chạy) → host bỏ lớp che nội dung page cũ.\n notify(CONTEXT_APPLIED);\n return;\n }\n emit(state, message.event, message.data);\n return;\n }\n const pending = state.pending.get(message.id);\n if (!pending) {\n return;\n }\n state.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.reject(MiniAppError.from(message.error, pending.method));\n } else {\n pending.resolve(message.result);\n }\n },\n };\n return state;\n};\n\nconst emit = (state: BridgeState, event: string, data: unknown) => {\n state.listeners.get(event)?.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`[retion-miniapp] listener \"${event}\" lỗi`, error);\n }\n });\n};\n\nlet fallback_state: BridgeState | null = null;\n\n/** @internal */\nexport const getState = (): BridgeState => {\n if (!hasWindow) {\n return (fallback_state ??= createState());\n }\n return (window.__RETION_MINIAPP__ ??= createState());\n};\n\n/** Đang chạy trong app Retion có hỗ trợ SDK (host đã inject marker + kênh postMessage). */\nexport const isInHost = (): boolean =>\n hasWindow &&\n typeof window.__RETION_MINIAPP_HOST__?.protocol === 'number' &&\n typeof window.ReactNativeWebView?.postMessage === 'function';\n\nconst post = (message: RequestMessage) => {\n window.ReactNativeWebView!.postMessage(JSON.stringify(message));\n};\n\n/** Gửi lệnh lên host và chờ kết quả. Ngoài app → reject NOT_IN_HOST. */\nexport const call = <T>(method: string, params?: unknown, timeout_ms = DEFAULT_TIMEOUT_MS): Promise<T> => {\n const state = getState();\n\n if (!isInHost()) {\n return Promise.reject(new MiniAppError(ErrorCode.NOT_IN_HOST, `${method} chỉ chạy trong app Retion`, method));\n }\n\n const id = `${Date.now().toString(36)}-${++state.seq}`;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id);\n reject(new MiniAppError(ErrorCode.TIMEOUT, `${method}: host không phản hồi sau ${timeout_ms}ms`, method));\n }, timeout_ms);\n state.pending.set(id, { method, resolve: resolve as (v: unknown) => void, reject, timer });\n post({ __retion: PROTOCOL_VERSION, id, method, params });\n });\n};\n\n/** Lệnh 1 chiều (không chờ kết quả). Ngoài app: bỏ qua. */\nexport const notify = (method: string, params?: unknown): void => {\n if (isInHost()) {\n post({ __retion: PROTOCOL_VERSION, method, params });\n }\n};\n\n/** Lắng nghe event host đẩy xuống. Trả về hàm huỷ. */\nexport const on = (event: string, listener: Listener): (() => void) => {\n const { listeners } = getState();\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n};\n","declare const __SDK_VERSION__: string;\n\n/** Thay lúc build (tsup define) / test (vitest define) bằng version trong package.json. */\nexport const SDK_VERSION: string = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n","import { call, notify, on } from '../bridge';\nimport { SDK_VERSION } from '../version';\n\n/**\n * Đóng mini app, quay về màn chat. Ngoài app → reject NOT_IN_HOST (web tự xử lý, vd router.back()).\n */\nexport const closeApp = (): Promise<void> => call<void>('closeApp');\n\n/** @internal SDK tự gọi khi trang sẵn sàng — host ẩn splash + đẩy context mới nhất. */\nexport const notifyReady = (): void => notify('ready', { sdkVersion: SDK_VERSION });\n\n/**\n * Mini app bị đóng (ẩn, vẫn chạy ngầm) — dừng polling / timer / video ở đây cho đỡ tốn pin.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppPaused = (listener: () => void): (() => void) => on('paused', () => listener());\n\n/**\n * Mini app được mở lại (trang vẫn giữ nguyên) — làm mới dữ liệu nếu cần.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppResumed = (listener: () => void): (() => void) => on('resumed', () => listener());\n","import { CONTEXT_EVENT, getState, on } from '../bridge';\nimport type { RouteParams } from '../types';\n\n/**\n * Thông tin conversation lúc mở mini app (đồng bộ, gọi bất cứ lúc nào).\n * @example\n * const { page_id, client_id } = getRouteParams();\n */\nexport const getRouteParams = (): RouteParams => ({ ...getState().context });\n\n/**\n * Mini app đang mở sẵn được mở lại ở conversation khác (khác page / khách, cùng tổ chức).\n * App không nạp lại trang → gọi lại API theo thông tin mới ở đây. Đổi tổ chức thì app nạp lại trang.\n * @returns hàm huỷ lắng nghe\n * @example\n * onContextChange(({ page_id, client_id }) => loadData(page_id, client_id));\n */\nexport const onContextChange = (listener: (next: RouteParams, prev: RouteParams) => void): (() => void) =>\n on(CONTEXT_EVENT, (data) => {\n const { next, prev } = data as { next: RouteParams; prev: RouteParams };\n listener(next, prev);\n });\n","import { call, isInHost } from '../bridge';\nimport { ErrorCode, MiniAppError } from '../errors';\n\n/** Tên query param chứa token khi chạy ngoài app (giống URL iframe hiện tại). */\nconst TOKEN_QUERY_PARAM = 'access_token';\n\nconst readTokenFromUrl = (): string | null => {\n if (typeof window === 'undefined') {\n return null;\n }\n return new URLSearchParams(window.location.search).get(TOKEN_QUERY_PARAM);\n};\n\n/**\n * Token để mini app gọi API backend của chính mình (Authorization: Bearer ...).\n * - Trong app: lấy từ host, luôn là token của page hiện tại, host tự refresh.\n * - Ngoài app: đọc `?access_token=` trên URL (như iframe hiện tại).\n * Gọi lại mỗi khi cần — không lưu token lâu phía web.\n */\nexport const getAccessToken = async (): Promise<string> => {\n if (isInHost()) {\n return call<string>('getAccessToken');\n }\n const token = readTokenFromUrl();\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${TOKEN_QUERY_PARAM}= trên URL`, 'getAccessToken');\n }\n return token;\n};\n\n/** Loại token: `access` luôn được phép; `partner` / `chatbox` cần admin bật quyền trên Console. */\nexport type TokenType = 'access' | 'partner' | 'chatbox';\n\n/** Tên query param tương ứng khi chạy ngoài app (giống URL iframe hiện tại). */\nconst QUERY_PARAM: Record<TokenType, string> = {\n access: 'access_token',\n partner: 'partner_token',\n chatbox: 'chatbox_token',\n};\n\n/**\n * Lấy token theo loại.\n * - `access`: token của mini app cho page hiện tại (= getAccessToken()).\n * - `partner`: token đối tác của page — cần quyền `partner_token`.\n * - `chatbox`: token đăng nhập của người dùng app (toàn quyền) — cần quyền `chatbox_token`.\n * Trong app, chưa được cấp quyền → MiniAppError PERMISSION_DENIED. Ngoài app: đọc query URL.\n */\nexport const getToken = async (type: TokenType): Promise<string> => {\n if (!(type in QUERY_PARAM)) {\n throw new MiniAppError(ErrorCode.HOST_ERROR, `Loại token không hợp lệ: ${String(type)}`, 'getToken');\n }\n if (isInHost()) {\n return call<string>('getToken', { type });\n }\n const token = typeof window === 'undefined' ? null : new URLSearchParams(window.location.search).get(QUERY_PARAM[type]);\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${QUERY_PARAM[type]}= trên URL`, 'getToken');\n }\n return token;\n};\n","import { call, notify } from '../bridge';\n\n/**\n * Chức năng native do app cung cấp (thanh toán, in, mở màn hình của app).\n * Mỗi app tự cài phần xử lý — app không hỗ trợ → MiniAppError NOT_SUPPORTED (web ẩn nút / báo người dùng).\n * Người dùng huỷ (đóng màn thanh toán, không chọn máy in…) → MiniAppError CANCELLED.\n * Đang thanh toán / in mà gọi lần nữa (bấm 2 lần) → MiniAppError BUSY — lượt đầu vẫn chạy bình thường.\n */\n\n/** Chờ người dùng thao tác (chạm thẻ, chọn máy in) — lâu hơn timeout mặc định 15s. */\nconst USER_ACTION_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport interface PaymentRequest {\n /** Số tiền theo đơn vị tiền tệ (vd 12.5 = 12,50 CAD). */\n amount: number;\n /** Mã tiền tệ ISO 4217: CAD, USD, VND… */\n currency: string;\n /** Mã đơn của bạn — app gắn vào giao dịch để đối soát. */\n order_id?: string;\n /** Ghi chú hiện trên giao dịch. */\n note?: string;\n /** Dữ liệu thêm app cần (vd chi tiết đơn) — tuỳ app. */\n metadata?: Record<string, unknown>;\n}\n\nexport interface PaymentResult {\n /** Mã giao dịch phía cổng thanh toán. */\n transaction_id: string;\n /** Cổng thanh toán: SQUARE, STRIPE, VNPAY… */\n provider: string;\n [key: string]: unknown;\n}\n\n/**\n * Thanh toán qua cổng của app (vd Tap to Pay). Resolve khi thanh toán thành công.\n * Luôn đối soát lại qua backend theo `order_id`: web có thể đóng / hết thời gian chờ trong khi giao dịch\n * phía app vẫn thành công.\n * @example\n * const { transaction_id, provider } = await requestPayment({ amount: 12.5, currency: 'CAD', order_id });\n */\nexport const requestPayment = (request: PaymentRequest): Promise<PaymentResult> =>\n call<PaymentResult>('requestPayment', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface PrintImageRequest {\n /** Ảnh hoá đơn base64 — có hoặc không có tiền tố `data:image/png;base64,`. */\n image: string;\n}\n\n/**\n * In ảnh (hoá đơn) ra máy in của app. App tự hiện chọn máy in nếu cần. Resolve khi in xong.\n */\nexport const printImage = (request: PrintImageRequest): Promise<void> =>\n call<void>('printImage', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface OpenScreenRequest {\n /** Tên màn hình app định nghĩa (vd `conversation`, `customer`) — xem tài liệu của app. */\n screen: string;\n params?: Record<string, unknown>;\n}\n\n/**\n * Mở 1 màn hình của app (app đóng mini app rồi chuyển màn). Màn không tồn tại → NOT_SUPPORTED.\n * @example\n * await openScreen({ screen: 'customer', params: { customer_id } });\n */\nexport const openScreen = (request: OpenScreenRequest): Promise<void> =>\n call<void>('openScreen', request);\n\n/**\n * Mở link bằng hệ điều hành — deeplink sang app khác (retion://…), tel:, mailto:, https (trình duyệt ngoài).\n * Không ứng dụng nào mở được (chưa cài app đích) / app chưa hỗ trợ → NOT_SUPPORTED (web tự mở link dự phòng).\n * @example\n * await openLink('retion://chat').catch(() => window.open(store_url, '_blank'));\n */\nexport const openLink = (url: string): Promise<void> => call<void>('openLink', { url });\n\n/**\n * Kiểu rung phản hồi — tên y hệt react-native-haptic-feedback: `haptic(HapticType.notificationSuccess)`.\n * - selection: đổi lựa chọn (tab, picker, toggle)\n * - impactLight / impactMedium / impactHeavy / rigid / soft: va chạm (bấm nút, kéo thả)\n * - notificationSuccess / notificationWarning / notificationError: kết quả thao tác\n */\nexport const HapticType = {\n selection: 'selection',\n impactLight: 'impactLight',\n impactMedium: 'impactMedium',\n impactHeavy: 'impactHeavy',\n rigid: 'rigid',\n soft: 'soft',\n notificationSuccess: 'notificationSuccess',\n notificationWarning: 'notificationWarning',\n notificationError: 'notificationError',\n} as const;\n\nexport type HapticType = (typeof HapticType)[keyof typeof HapticType];\n\n/**\n * Rung phản hồi — gọi lúc nào cũng được, không chờ kết quả. Ngoài app / app chưa hỗ trợ → bỏ qua.\n * @example\n * haptic(HapticType.impactLight); // bấm nút\n * await requestPayment(request); haptic(HapticType.notificationSuccess);\n */\nexport const haptic = (type: HapticType = HapticType.selection): void => notify('haptic', { type });\n","import { call } from '../bridge';\n\nexport type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';\nexport interface BiometricAvailability {\n available: boolean;\n biometryType?: BiometryType;\n}\nexport interface BiometricRequest {\n /** Text shown in the operating system authentication prompt (1–200 characters). */\n reason: string;\n cancelButtonText?: string;\n}\n\n/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */\nexport const getBiometricAvailability = (): Promise<BiometricAvailability> =>\n call<BiometricAvailability>('getBiometricAvailability');\n\n/** Local verification only. Rejects on cancellation/failure; never returns biometric data or a login token. */\nexport const authenticateBiometric = (request: BiometricRequest): Promise<{ success: true }> =>\n call<{ success: true }>('authenticateBiometric', request, 10 * 60 * 1000);\n","import { getState } from './bridge';\nimport { notifyReady } from './apis/app';\n\nexport { getRouteParams, onContextChange } from './apis/route';\nexport { getAccessToken, getToken, type TokenType } from './apis/user';\nexport { closeApp, onAppPaused, onAppResumed } from './apis/app';\nexport {\n haptic,\n HapticType,\n openLink,\n openScreen,\n printImage,\n requestPayment,\n type OpenScreenRequest,\n type PaymentRequest,\n type PaymentResult,\n type PrintImageRequest,\n} from './apis/native';\nexport { isInHost } from './bridge';\nexport { MiniAppError, ErrorCode } from './errors';\nexport { SDK_VERSION } from './version';\nexport type { RouteParams } from './types';\n\n// Khởi tạo bridge ngay khi import (host có thể đẩy context trước khi app gọi hàm nào),\n// rồi báo \"ready\" khi DOM sẵn sàng.\nif (typeof window !== 'undefined') {\n getState();\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', notifyReady, { once: true });\n } else {\n queueMicrotask(notifyReady);\n }\n}\n\nexport { getBiometricAvailability, authenticateBiometric, type BiometryType, type BiometricAvailability, type BiometricRequest } from './apis/biometrics';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/bridge.ts","../src/version.ts","../src/apis/app.ts","../src/apis/route.ts","../src/apis/user.ts","../src/apis/native.ts","../src/apis/biometrics.ts","../src/apis/speech.ts","../src/index.ts"],"names":[],"mappings":";;;AAAO,IAAM,SAAA,GAAY;AAAA,EACvB,cAAA,EAAgB,gBAAA;AAAA,EAChB,qBAAA,EAAuB,uBAAA;AAAA,EACvB,qBAAA,EAAuB,uBAAA;AAAA;AAAA,EAEvB,WAAA,EAAa,aAAA;AAAA;AAAA,EAEb,OAAA,EAAS,SAAA;AAAA;AAAA,EAET,iBAAA,EAAmB,mBAAA;AAAA;AAAA,EAEnB,aAAA,EAAe,eAAA;AAAA;AAAA,EAEf,SAAA,EAAW,WAAA;AAAA;AAAA,EAEX,IAAA,EAAM,MAAA;AAAA;AAAA,EAEN,UAAA,EAAY;AACd;AAIO,IAAM,YAAA,GAAN,MAAM,aAAA,SAAqB,KAAA,CAAM;AAAA,EAItC,WAAA,CAAY,IAAA,EAAiB,OAAA,EAAiB,MAAA,EAAiB;AAC7D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA,EAGA,OAAO,IAAA,CAAK,KAAA,EAAgB,MAAA,EAA+B;AACzD,IAAA,IAAI,iBAAiB,aAAA,EAAc;AACjC,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,MAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAQ,GAAI,KAAA;AAC1B,MAAA,OAAO,IAAI,aAAA;AAAA,QACT,OAAO,IAAA,KAAS,QAAA,GAAW,IAAA,GAAO,SAAA,CAAU,UAAA;AAAA,QAC5C,OAAO,OAAA,KAAY,QAAA,GAAW,OAAA,GAAU,eAAA;AAAA,QACxC;AAAA,OACF;AAAA,IACF;AACA,IAAA,OAAO,IAAI,aAAA,CAAa,SAAA,CAAU,YAAY,MAAA,CAAO,KAAK,GAAG,MAAM,CAAA;AAAA,EACrE;AACF;;;AC5BO,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,kBAAA,GAAqB,IAAA;AAC3B,IAAM,aAAA,GAAgB,SAAA;AAEtB,IAAM,eAAA,GAAkB,gBAAA;AAmD/B,IAAM,SAAA,GAAY,OAAO,MAAA,KAAW,WAAA;AAEpC,IAAM,qBAAqB,MAAmB;AA7E9C,EAAA,IAAA,EAAA;AA8EE,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,KAAA,GAAQ,OAAO,WAAA,CAAY,IAAI,gBAAgB,MAAA,CAAO,QAAA,CAAS,MAAM,CAAC,CAAA;AAC5E,EAAA,OAAO,EAAE,GAAG,KAAA,EAAO,GAAA,CAAI,YAAO,0BAAA,KAAP,IAAA,GAAA,EAAA,GAAqC,EAAC,EAAG;AAClE,CAAA;AAEA,IAAM,cAAc,MAAmB;AACrC,EAAA,MAAM,KAAA,GAAqB;AAAA,IACzB,QAAA,EAAU,gBAAA;AAAA,IACV,GAAA,EAAK,CAAA;AAAA,IACL,OAAA,sBAAa,GAAA,EAAI;AAAA,IACjB,SAAA,sBAAe,GAAA,EAAI;AAAA,IACnB,SAAS,kBAAA,EAAmB;AAAA,IAC5B,OAAA,EAAS,CAAC,OAAA,KAAY;AACpB,MAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC3C,QAAA;AAAA,MACF;AACA,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,IAAI,OAAA,CAAQ,UAAU,aAAA,EAAe;AAEnC,UAAA,MAAM,OAAO,KAAA,CAAM,OAAA;AAGnB,UAAA,MAAM,IAAA,GAAO,EAAE,GAAI,OAAA,CAAQ,IAAA,EAAqB;AAEhD,UAAA,IAAI,KAAK,SAAA,CAAU,IAAI,MAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA,EAAG;AACjD,YAAA,KAAA,CAAM,OAAA,GAAU,IAAA;AAChB,YAAA,IAAA,CAAK,KAAA,EAAO,eAAe,EAAE,IAAA,EAAM,EAAE,GAAG,IAAA,EAAK,EAAG,IAAA,EAAM,CAAA;AAAA,UACxD;AAEA,UAAA,MAAA,CAAO,eAAe,CAAA;AACtB,UAAA;AAAA,QACF;AACA,QAAA,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,OAAA,CAAQ,IAAI,CAAA;AACvC,QAAA;AAAA,MACF;AACA,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,QAAQ,EAAE,CAAA;AAC5C,MAAA,IAAI,CAAC,OAAA,EAAS;AACZ,QAAA;AAAA,MACF;AACA,MAAA,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,EAAE,CAAA;AAC/B,MAAA,YAAA,CAAa,QAAQ,KAAK,CAAA;AAC1B,MAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,QAAA,OAAA,CAAQ,OAAO,YAAA,CAAa,IAAA,CAAK,QAAQ,KAAA,EAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,MACjE,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,MAChC;AAAA,IACF;AAAA,GACF;AACA,EAAA,OAAO,KAAA;AACT,CAAA;AAEA,IAAM,IAAA,GAAO,CAAC,KAAA,EAAoB,KAAA,EAAe,IAAA,KAAkB;AAnInE,EAAA,IAAA,EAAA;AAoIE,EAAA,CAAA,EAAA,GAAA,KAAA,CAAM,UAAU,GAAA,CAAI,KAAK,MAAzB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA4B,OAAA,CAAQ,CAAC,QAAA,KAAa;AAChD,IAAA,IAAI;AACF,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,2BAAA,EAA8B,KAAK,CAAA,UAAA,CAAA,EAAS,KAAK,CAAA;AAAA,IACjE;AAAA,EACF,CAAA,CAAA;AACF,CAAA;AAEA,IAAI,cAAA,GAAqC,IAAA;AAGlC,IAAM,WAAW,MAAmB;AAhJ3C,EAAA,IAAA,EAAA;AAiJE,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAQ,2DAAmB,WAAA,EAAY;AAAA,EACzC;AACA,EAAA,OAAA,CAAQ,EAAA,GAAA,MAAA,CAAO,kBAAA,KAAP,IAAA,GAAA,EAAA,GAAA,MAAA,CAAO,kBAAA,GAAuB,WAAA,EAAY;AACpD,CAAA;AAGO,IAAM,WAAW,MAAY;AAxJpC,EAAA,IAAA,EAAA,EAAA,EAAA;AAyJE,EAAA,OAAA,SAAA,IACA,QAAA,CAAO,EAAA,GAAA,MAAA,CAAO,uBAAA,KAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAgC,QAAA,CAAA,KAAa,YACpD,QAAA,CAAO,EAAA,GAAA,MAAA,CAAO,kBAAA,KAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAA2B,WAAA,CAAA,KAAgB,UAAA;AAAA;AAEpD,IAAM,IAAA,GAAO,CAAC,OAAA,KAA4B;AACxC,EAAA,MAAA,CAAO,kBAAA,CAAoB,WAAA,CAAY,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAChE,CAAA;AAGO,IAAM,IAAA,GAAO,CAAI,MAAA,EAAgB,MAAA,EAAkB,aAAa,kBAAA,KAAmC;AACxG,EAAA,MAAM,QAAQ,QAAA,EAAS;AAEvB,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,YAAA,CAAa,SAAA,CAAU,aAAa,CAAA,EAAG,MAAM,CAAA,oCAAA,CAAA,EAA8B,MAAM,CAAC,CAAA;AAAA,EAC9G;AAEA,EAAA,MAAM,EAAA,GAAK,CAAA,EAAG,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA,EAAI,EAAE,KAAA,CAAM,GAAG,CAAA,CAAA;AACpD,EAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AACzC,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,MAAA,KAAA,CAAM,OAAA,CAAQ,OAAO,EAAE,CAAA;AACvB,MAAA,MAAA,CAAO,IAAI,YAAA,CAAa,SAAA,CAAU,OAAA,EAAS,CAAA,EAAG,MAAM,CAAA,uCAAA,EAA6B,UAAU,CAAA,EAAA,CAAA,EAAM,MAAM,CAAC,CAAA;AAAA,IAC1G,GAAG,UAAU,CAAA;AACb,IAAA,KAAA,CAAM,OAAA,CAAQ,IAAI,EAAA,EAAI,EAAE,QAAQ,OAAA,EAA0C,MAAA,EAAQ,OAAO,CAAA;AACzF,IAAA,IAAA,CAAK,EAAE,QAAA,EAAU,gBAAA,EAAkB,EAAA,EAAI,MAAA,EAAQ,QAAQ,CAAA;AAAA,EACzD,CAAC,CAAA;AACH,CAAA;AAGO,IAAM,MAAA,GAAS,CAAC,MAAA,EAAgB,MAAA,KAA2B;AAChE,EAAA,IAAI,UAAS,EAAG;AACd,IAAA,IAAA,CAAK,EAAE,QAAA,EAAU,gBAAA,EAAkB,MAAA,EAAQ,QAAQ,CAAA;AAAA,EACrD;AACF,CAAA;AAGO,IAAM,EAAA,GAAK,CAAC,KAAA,EAAe,QAAA,KAAqC;AACrE,EAAA,MAAM,EAAE,SAAA,EAAU,GAAI,QAAA,EAAS;AAC/B,EAAA,IAAI,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,KAAK,CAAA;AAC7B,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,GAAA,uBAAU,GAAA,EAAI;AACd,IAAA,SAAA,CAAU,GAAA,CAAI,OAAO,GAAG,CAAA;AAAA,EAC1B;AACA,EAAA,GAAA,CAAI,IAAI,QAAQ,CAAA;AAChB,EAAA,OAAO,MAAM;AACX,IAAA,GAAA,CAAI,OAAO,QAAQ,CAAA;AAAA,EACrB,CAAA;AACF,CAAA;;;ACpMO,IAAM,WAAA,GAA4D,OAAA;;;ACGlE,IAAM,QAAA,GAAW,MAAqB,IAAA,CAAW,UAAU;AAG3D,IAAM,cAAc,MAAY,MAAA,CAAO,SAAS,EAAE,UAAA,EAAY,aAAa,CAAA;AAM3E,IAAM,cAAc,CAAC,QAAA,KAAuC,GAAG,QAAA,EAAU,MAAM,UAAU;AAMzF,IAAM,eAAe,CAAC,QAAA,KAAuC,GAAG,SAAA,EAAW,MAAM,UAAU;;;ACb3F,IAAM,iBAAiB,OAAoB,EAAE,GAAG,QAAA,GAAW,OAAA,EAAQ;AASnE,IAAM,kBAAkB,CAAC,QAAA,KAC9B,EAAA,CAAG,aAAA,EAAe,CAAC,IAAA,KAAS;AAC1B,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,IAAA;AACvB,EAAA,QAAA,CAAS,MAAM,IAAI,CAAA;AACrB,CAAC;;;ACjBH,IAAM,iBAAA,GAAoB,cAAA;AAE1B,IAAM,mBAAmB,MAAqB;AAC5C,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAI,eAAA,CAAgB,MAAA,CAAO,SAAS,MAAM,CAAA,CAAE,IAAI,iBAAiB,CAAA;AAC1E,CAAA;AAQO,IAAM,iBAAiB,YAA6B;AACzD,EAAA,IAAI,UAAS,EAAG;AACd,IAAA,OAAO,KAAa,gBAAgB,CAAA;AAAA,EACtC;AACA,EAAA,MAAM,QAAQ,gBAAA,EAAiB;AAC/B,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,YAAA,CAAa,SAAA,CAAU,aAAa,CAAA,0BAAA,EAAqB,iBAAiB,iBAAc,gBAAgB,CAAA;AAAA,EACpH;AACA,EAAA,OAAO,KAAA;AACT;AAMA,IAAM,WAAA,GAAyC;AAAA,EAC7C,MAAA,EAAQ,cAAA;AAAA,EACR,OAAA,EAAS,eAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAA;AASO,IAAM,QAAA,GAAW,OAAO,IAAA,KAAqC;AAClE,EAAA,IAAI,EAAE,QAAQ,WAAA,CAAA,EAAc;AAC1B,IAAA,MAAM,IAAI,aAAa,SAAA,CAAU,UAAA,EAAY,8CAA4B,MAAA,CAAO,IAAI,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA;AAAA,EACrG;AACA,EAAA,IAAI,UAAS,EAAG;AACd,IAAA,OAAO,IAAA,CAAa,UAAA,EAAY,EAAE,IAAA,EAAM,CAAA;AAAA,EAC1C;AACA,EAAA,MAAM,KAAA,GAAQ,OAAO,MAAA,KAAW,WAAA,GAAc,OAAO,IAAI,eAAA,CAAgB,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAE,GAAA,CAAI,WAAA,CAAY,IAAI,CAAC,CAAA;AACtH,EAAA,IAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,aAAa,SAAA,CAAU,WAAA,EAAa,6BAAqB,WAAA,CAAY,IAAI,CAAC,CAAA,aAAA,CAAA,EAAc,UAAU,CAAA;AAAA,EAC9G;AACA,EAAA,OAAO,KAAA;AACT;;;ACjDA,IAAM,sBAAA,GAAyB,KAAK,EAAA,GAAK,GAAA;AA8BlC,IAAM,iBAAiB,CAAC,OAAA,KAC7B,IAAA,CAAoB,gBAAA,EAAkB,SAAS,sBAAsB;AAUhE,IAAM,aAAa,CAAC,OAAA,KACzB,IAAA,CAAW,YAAA,EAAc,SAAS,sBAAsB;AAanD,IAAM,UAAA,GAAa,CAAC,OAAA,KACzB,IAAA,CAAW,cAAc,OAAO;AAQ3B,IAAM,WAAW,CAAC,GAAA,KAA+B,KAAW,UAAA,EAAY,EAAE,KAAK;AAQ/E,IAAM,UAAA,GAAa;AAAA,EACxB,SAAA,EAAW,WAAA;AAAA,EACX,WAAA,EAAa,aAAA;AAAA,EACb,YAAA,EAAc,cAAA;AAAA,EACd,WAAA,EAAa,aAAA;AAAA,EACb,KAAA,EAAO,OAAA;AAAA,EACP,IAAA,EAAM,MAAA;AAAA,EACN,mBAAA,EAAqB,qBAAA;AAAA,EACrB,mBAAA,EAAqB,qBAAA;AAAA,EACrB,iBAAA,EAAmB;AACrB;AAUO,IAAM,MAAA,GAAS,CAAC,IAAA,GAAmB,UAAA,CAAW,cAAoB,MAAA,CAAO,QAAA,EAAU,EAAE,IAAA,EAAM;;;ACvF3F,IAAM,wBAAA,GAA2B,MACtC,IAAA,CAA4B,0BAA0B;AASjD,IAAM,qBAAA,GAAwB,CAAC,OAAA,KACpC,IAAA,CAAsB,yBAAyB,OAAA,EAAS,EAAA,GAAK,KAAK,GAAI;;;ACFjE,IAAM,WAAA,GAAc,CAAC,OAAA,GAAyB,OAAsB,IAAA,CAAW,cAAA,EAAgB,SAAS,IAAO;AAE/G,IAAM,UAAA,GAAa,MAAqB,IAAA,CAAW,aAAa;AAEhE,IAAM,QAAA,GAAW,CAA+B,KAAA,EAAU,QAAA,KAC/D,GAAG,KAAA,EAAO,CAAA,IAAA,KAAQ,QAAA,CAAS,IAAuB,CAAC;;;ACJrD,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,EAAA,QAAA,EAAS;AACT,EAAA,IAAI,QAAA,CAAS,eAAe,SAAA,EAAW;AACrC,IAAA,QAAA,CAAS,iBAAiB,kBAAA,EAAoB,WAAA,EAAa,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC3E,CAAA,MAAO;AACL,IAAA,cAAA,CAAe,WAAW,CAAA;AAAA,EAC5B;AACF","file":"index.cjs","sourcesContent":["export const ErrorCode = {\n INVALID_PARAMS: 'INVALID_PARAMS',\n BIOMETRIC_UNAVAILABLE: 'BIOMETRIC_UNAVAILABLE',\n AUTHENTICATION_FAILED: 'AUTHENTICATION_FAILED',\n /** Không chạy trong app Retion (trình duyệt / iframe cũ). */\n NOT_IN_HOST: 'NOT_IN_HOST',\n /** Host không phản hồi trong thời gian chờ. */\n TIMEOUT: 'TIMEOUT',\n /** Mini app chưa được admin cấp quyền (vd lấy partner_token / chatbox_token). */\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n /** Host (phiên bản app hiện tại) chưa hỗ trợ API này. */\n NOT_SUPPORTED: 'NOT_SUPPORTED',\n /** Người dùng huỷ thao tác (đóng màn thanh toán, không chọn máy in…). */\n CANCELLED: 'CANCELLED',\n /** Đang có 1 lượt cùng loại chạy (vd đang thanh toán mà gọi requestPayment lần nữa). */\n BUSY: 'BUSY',\n /** Lỗi khác phía host. */\n HOST_ERROR: 'HOST_ERROR',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode] | (string & {});\n\nexport class MiniAppError extends Error {\n readonly code: ErrorCode;\n readonly method?: string;\n\n constructor(code: ErrorCode, message: string, method?: string) {\n super(message);\n this.name = 'MiniAppError';\n this.code = code;\n this.method = method;\n }\n\n /** Chuẩn hoá lỗi từ host (object thuần, Error, string) về MiniAppError. */\n static from(error: unknown, method?: string): MiniAppError {\n if (error instanceof MiniAppError) {\n return error;\n }\n if (error && typeof error === 'object') {\n const { code, message } = error as { code?: unknown; message?: unknown };\n return new MiniAppError(\n typeof code === 'string' ? code : ErrorCode.HOST_ERROR,\n typeof message === 'string' ? message : 'Unknown error',\n method,\n );\n }\n return new MiniAppError(ErrorCode.HOST_ERROR, String(error), method);\n }\n}\n","/**\n * Bridge web mini app ↔ host (app Retion). Nội bộ SDK — dev mini app không import trực tiếp.\n *\n * Giao thức v1\n * web → host : ReactNativeWebView.postMessage(JSON.stringify(RequestMessage))\n * host → web : window.__RETION_MINIAPP__.receive(ResponseMessage | EventMessage)\n * host → web event \"context\" → web gọi onContextChange → web → host \"contextApplied\"\n * host inject trước khi trang chạy:\n * window.__RETION_MINIAPP_HOST__ = { protocol } ← đánh dấu host hỗ trợ SDK\n * window.__RETION_MINIAPP_CONTEXT__ = RouteParams ← context ban đầu\n *\n * Chỉ có ReactNativeWebView KHÔNG đủ để coi là host: màn iframe cũ của app cũng là RN WebView\n * nhưng không hiểu giao thức này (gọi API sẽ treo tới timeout). Thiếu marker → NOT_IN_HOST ngay.\n *\n * State đặt trên window (singleton): nhiều bản SDK trong cùng trang (trùng version trong\n * node_modules) vẫn dùng chung 1 bridge thay vì ghi đè hàm receive của nhau.\n */\nimport { ErrorCode, MiniAppError } from './errors';\nimport type { RouteParams } from './types';\n\nexport const PROTOCOL_VERSION = 1;\nexport const DEFAULT_TIMEOUT_MS = 15_000;\nexport const CONTEXT_EVENT = 'context';\n/** web → host: đã áp dụng context mới (sau khi gọi các listener onContextChange). */\nexport const CONTEXT_APPLIED = 'contextApplied';\n\nexport interface RequestMessage {\n __retion: typeof PROTOCOL_VERSION;\n /** Có id → host phải trả ResponseMessage. Không có → lệnh 1 chiều. */\n id?: string;\n method: string;\n params?: unknown;\n}\n\nexport type ResponseMessage =\n | { id: string; result?: unknown; error?: undefined }\n | { id: string; error: { code: string; message: string } };\n\nexport interface EventMessage {\n event: string;\n data?: unknown;\n}\n\nexport interface HostInfo {\n /** Phiên bản giao thức host hỗ trợ. */\n protocol: number;\n}\n\ntype Listener = (data: unknown) => void;\n\ninterface Pending {\n method: string;\n resolve: (value: unknown) => void;\n reject: (error: MiniAppError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface BridgeState {\n protocol: number;\n seq: number;\n pending: Map<string, Pending>;\n listeners: Map<string, Set<Listener>>;\n context: RouteParams;\n receive: (message: ResponseMessage | EventMessage) => void;\n}\n\ndeclare global {\n interface Window {\n ReactNativeWebView?: { postMessage: (message: string) => void };\n __RETION_MINIAPP__?: BridgeState;\n __RETION_MINIAPP_CONTEXT__?: RouteParams;\n __RETION_MINIAPP_HOST__?: HostInfo;\n }\n}\n\nconst hasWindow = typeof window !== 'undefined';\n\nconst readInitialContext = (): RouteParams => {\n if (!hasWindow) {\n return {};\n }\n const query = Object.fromEntries(new URLSearchParams(window.location.search));\n return { ...query, ...(window.__RETION_MINIAPP_CONTEXT__ ?? {}) };\n};\n\nconst createState = (): BridgeState => {\n const state: BridgeState = {\n protocol: PROTOCOL_VERSION,\n seq: 0,\n pending: new Map(),\n listeners: new Map(),\n context: readInitialContext(),\n receive: (message) => {\n if (!message || typeof message !== 'object') {\n return;\n }\n if ('event' in message) {\n if (message.event === CONTEXT_EVENT) {\n // Cập nhật context TRƯỚC khi emit → getRouteParams() luôn đúng, kể cả không ai lắng nghe.\n const prev = state.context;\n // Host luôn gửi ĐỦ context của lần mở → thay hẳn, không gộp với context cũ: gộp thì param\n // lần trước không còn (vd. message_id khi mở từ nút CTA rồi mở lại từ menu) vẫn bị giữ lại.\n const next = { ...(message.data as RouteParams) };\n // Host đẩy lại context lúc \"ready\" dù không đổi → không báo onContextChange thừa.\n if (JSON.stringify(next) !== JSON.stringify(prev)) {\n state.context = next;\n emit(state, CONTEXT_EVENT, { next: { ...next }, prev });\n }\n // Báo host: web đã nhận context (listener đã chạy) → host bỏ lớp che nội dung page cũ.\n notify(CONTEXT_APPLIED);\n return;\n }\n emit(state, message.event, message.data);\n return;\n }\n const pending = state.pending.get(message.id);\n if (!pending) {\n return;\n }\n state.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.reject(MiniAppError.from(message.error, pending.method));\n } else {\n pending.resolve(message.result);\n }\n },\n };\n return state;\n};\n\nconst emit = (state: BridgeState, event: string, data: unknown) => {\n state.listeners.get(event)?.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`[retion-miniapp] listener \"${event}\" lỗi`, error);\n }\n });\n};\n\nlet fallback_state: BridgeState | null = null;\n\n/** @internal */\nexport const getState = (): BridgeState => {\n if (!hasWindow) {\n return (fallback_state ??= createState());\n }\n return (window.__RETION_MINIAPP__ ??= createState());\n};\n\n/** Đang chạy trong app Retion có hỗ trợ SDK (host đã inject marker + kênh postMessage). */\nexport const isInHost = (): boolean =>\n hasWindow &&\n typeof window.__RETION_MINIAPP_HOST__?.protocol === 'number' &&\n typeof window.ReactNativeWebView?.postMessage === 'function';\n\nconst post = (message: RequestMessage) => {\n window.ReactNativeWebView!.postMessage(JSON.stringify(message));\n};\n\n/** Gửi lệnh lên host và chờ kết quả. Ngoài app → reject NOT_IN_HOST. */\nexport const call = <T>(method: string, params?: unknown, timeout_ms = DEFAULT_TIMEOUT_MS): Promise<T> => {\n const state = getState();\n\n if (!isInHost()) {\n return Promise.reject(new MiniAppError(ErrorCode.NOT_IN_HOST, `${method} chỉ chạy trong app Retion`, method));\n }\n\n const id = `${Date.now().toString(36)}-${++state.seq}`;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id);\n reject(new MiniAppError(ErrorCode.TIMEOUT, `${method}: host không phản hồi sau ${timeout_ms}ms`, method));\n }, timeout_ms);\n state.pending.set(id, { method, resolve: resolve as (v: unknown) => void, reject, timer });\n post({ __retion: PROTOCOL_VERSION, id, method, params });\n });\n};\n\n/** Lệnh 1 chiều (không chờ kết quả). Ngoài app: bỏ qua. */\nexport const notify = (method: string, params?: unknown): void => {\n if (isInHost()) {\n post({ __retion: PROTOCOL_VERSION, method, params });\n }\n};\n\n/** Lắng nghe event host đẩy xuống. Trả về hàm huỷ. */\nexport const on = (event: string, listener: Listener): (() => void) => {\n const { listeners } = getState();\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n};\n","declare const __SDK_VERSION__: string;\n\n/** Thay lúc build (tsup define) / test (vitest define) bằng version trong package.json. */\nexport const SDK_VERSION: string = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n","import { call, notify, on } from '../bridge';\nimport { SDK_VERSION } from '../version';\n\n/**\n * Đóng mini app, quay về màn chat. Ngoài app → reject NOT_IN_HOST (web tự xử lý, vd router.back()).\n */\nexport const closeApp = (): Promise<void> => call<void>('closeApp');\n\n/** @internal SDK tự gọi khi trang sẵn sàng — host ẩn splash + đẩy context mới nhất. */\nexport const notifyReady = (): void => notify('ready', { sdkVersion: SDK_VERSION });\n\n/**\n * Mini app bị đóng (ẩn, vẫn chạy ngầm) — dừng polling / timer / video ở đây cho đỡ tốn pin.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppPaused = (listener: () => void): (() => void) => on('paused', () => listener());\n\n/**\n * Mini app được mở lại (trang vẫn giữ nguyên) — làm mới dữ liệu nếu cần.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppResumed = (listener: () => void): (() => void) => on('resumed', () => listener());\n","import { CONTEXT_EVENT, getState, on } from '../bridge';\nimport type { RouteParams } from '../types';\n\n/**\n * Thông tin conversation lúc mở mini app (đồng bộ, gọi bất cứ lúc nào).\n * @example\n * const { page_id, client_id } = getRouteParams();\n */\nexport const getRouteParams = (): RouteParams => ({ ...getState().context });\n\n/**\n * Mini app đang mở sẵn được mở lại ở conversation khác (khác page / khách, cùng tổ chức).\n * App không nạp lại trang → gọi lại API theo thông tin mới ở đây. Đổi tổ chức thì app nạp lại trang.\n * @returns hàm huỷ lắng nghe\n * @example\n * onContextChange(({ page_id, client_id }) => loadData(page_id, client_id));\n */\nexport const onContextChange = (listener: (next: RouteParams, prev: RouteParams) => void): (() => void) =>\n on(CONTEXT_EVENT, (data) => {\n const { next, prev } = data as { next: RouteParams; prev: RouteParams };\n listener(next, prev);\n });\n","import { call, isInHost } from '../bridge';\nimport { ErrorCode, MiniAppError } from '../errors';\n\n/** Tên query param chứa token khi chạy ngoài app (giống URL iframe hiện tại). */\nconst TOKEN_QUERY_PARAM = 'access_token';\n\nconst readTokenFromUrl = (): string | null => {\n if (typeof window === 'undefined') {\n return null;\n }\n return new URLSearchParams(window.location.search).get(TOKEN_QUERY_PARAM);\n};\n\n/**\n * Token để mini app gọi API backend của chính mình (Authorization: Bearer ...).\n * - Trong app: lấy từ host, luôn là token của page hiện tại, host tự refresh.\n * - Ngoài app: đọc `?access_token=` trên URL (như iframe hiện tại).\n * Gọi lại mỗi khi cần — không lưu token lâu phía web.\n */\nexport const getAccessToken = async (): Promise<string> => {\n if (isInHost()) {\n return call<string>('getAccessToken');\n }\n const token = readTokenFromUrl();\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${TOKEN_QUERY_PARAM}= trên URL`, 'getAccessToken');\n }\n return token;\n};\n\n/** Loại token: `access` luôn được phép; `partner` / `chatbox` cần admin bật quyền trên Console. */\nexport type TokenType = 'access' | 'partner' | 'chatbox';\n\n/** Tên query param tương ứng khi chạy ngoài app (giống URL iframe hiện tại). */\nconst QUERY_PARAM: Record<TokenType, string> = {\n access: 'access_token',\n partner: 'partner_token',\n chatbox: 'chatbox_token',\n};\n\n/**\n * Lấy token theo loại.\n * - `access`: token của mini app cho page hiện tại (= getAccessToken()).\n * - `partner`: token đối tác của page — cần quyền `partner_token`.\n * - `chatbox`: token đăng nhập của người dùng app (toàn quyền) — cần quyền `chatbox_token`.\n * Trong app, chưa được cấp quyền → MiniAppError PERMISSION_DENIED. Ngoài app: đọc query URL.\n */\nexport const getToken = async (type: TokenType): Promise<string> => {\n if (!(type in QUERY_PARAM)) {\n throw new MiniAppError(ErrorCode.HOST_ERROR, `Loại token không hợp lệ: ${String(type)}`, 'getToken');\n }\n if (isInHost()) {\n return call<string>('getToken', { type });\n }\n const token = typeof window === 'undefined' ? null : new URLSearchParams(window.location.search).get(QUERY_PARAM[type]);\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${QUERY_PARAM[type]}= trên URL`, 'getToken');\n }\n return token;\n};\n","import { call, notify } from '../bridge';\n\n/**\n * Chức năng native do app cung cấp (thanh toán, in, mở màn hình của app).\n * Mỗi app tự cài phần xử lý — app không hỗ trợ → MiniAppError NOT_SUPPORTED (web ẩn nút / báo người dùng).\n * Người dùng huỷ (đóng màn thanh toán, không chọn máy in…) → MiniAppError CANCELLED.\n * Đang thanh toán / in mà gọi lần nữa (bấm 2 lần) → MiniAppError BUSY — lượt đầu vẫn chạy bình thường.\n */\n\n/** Chờ người dùng thao tác (chạm thẻ, chọn máy in) — lâu hơn timeout mặc định 15s. */\nconst USER_ACTION_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport interface PaymentRequest {\n /** Số tiền theo đơn vị tiền tệ (vd 12.5 = 12,50 CAD). */\n amount: number;\n /** Mã tiền tệ ISO 4217: CAD, USD, VND… */\n currency: string;\n /** Mã đơn của bạn — app gắn vào giao dịch để đối soát. */\n order_id?: string;\n /** Ghi chú hiện trên giao dịch. */\n note?: string;\n /** Dữ liệu thêm app cần (vd chi tiết đơn) — tuỳ app. */\n metadata?: Record<string, unknown>;\n}\n\nexport interface PaymentResult {\n /** Mã giao dịch phía cổng thanh toán. */\n transaction_id: string;\n /** Cổng thanh toán: SQUARE, STRIPE, VNPAY… */\n provider: string;\n [key: string]: unknown;\n}\n\n/**\n * Thanh toán qua cổng của app (vd Tap to Pay). Resolve khi thanh toán thành công.\n * Luôn đối soát lại qua backend theo `order_id`: web có thể đóng / hết thời gian chờ trong khi giao dịch\n * phía app vẫn thành công.\n * @example\n * const { transaction_id, provider } = await requestPayment({ amount: 12.5, currency: 'CAD', order_id });\n */\nexport const requestPayment = (request: PaymentRequest): Promise<PaymentResult> =>\n call<PaymentResult>('requestPayment', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface PrintImageRequest {\n /** Ảnh hoá đơn base64 — có hoặc không có tiền tố `data:image/png;base64,`. */\n image: string;\n}\n\n/**\n * In ảnh (hoá đơn) ra máy in của app. App tự hiện chọn máy in nếu cần. Resolve khi in xong.\n */\nexport const printImage = (request: PrintImageRequest): Promise<void> =>\n call<void>('printImage', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface OpenScreenRequest {\n /** Tên màn hình app định nghĩa (vd `conversation`, `customer`) — xem tài liệu của app. */\n screen: string;\n params?: Record<string, unknown>;\n}\n\n/**\n * Mở 1 màn hình của app (app đóng mini app rồi chuyển màn). Màn không tồn tại → NOT_SUPPORTED.\n * @example\n * await openScreen({ screen: 'customer', params: { customer_id } });\n */\nexport const openScreen = (request: OpenScreenRequest): Promise<void> =>\n call<void>('openScreen', request);\n\n/**\n * Mở link bằng hệ điều hành — deeplink sang app khác (retion://…), tel:, mailto:, https (trình duyệt ngoài).\n * Không ứng dụng nào mở được (chưa cài app đích) / app chưa hỗ trợ → NOT_SUPPORTED (web tự mở link dự phòng).\n * @example\n * await openLink('retion://chat').catch(() => window.open(store_url, '_blank'));\n */\nexport const openLink = (url: string): Promise<void> => call<void>('openLink', { url });\n\n/**\n * Kiểu rung phản hồi — tên y hệt react-native-haptic-feedback: `haptic(HapticType.notificationSuccess)`.\n * - selection: đổi lựa chọn (tab, picker, toggle)\n * - impactLight / impactMedium / impactHeavy / rigid / soft: va chạm (bấm nút, kéo thả)\n * - notificationSuccess / notificationWarning / notificationError: kết quả thao tác\n */\nexport const HapticType = {\n selection: 'selection',\n impactLight: 'impactLight',\n impactMedium: 'impactMedium',\n impactHeavy: 'impactHeavy',\n rigid: 'rigid',\n soft: 'soft',\n notificationSuccess: 'notificationSuccess',\n notificationWarning: 'notificationWarning',\n notificationError: 'notificationError',\n} as const;\n\nexport type HapticType = (typeof HapticType)[keyof typeof HapticType];\n\n/**\n * Rung phản hồi — gọi lúc nào cũng được, không chờ kết quả. Ngoài app / app chưa hỗ trợ → bỏ qua.\n * @example\n * haptic(HapticType.impactLight); // bấm nút\n * await requestPayment(request); haptic(HapticType.notificationSuccess);\n */\nexport const haptic = (type: HapticType = HapticType.selection): void => notify('haptic', { type });\n","import { call } from '../bridge';\n\nexport type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';\nexport interface BiometricAvailability {\n available: boolean;\n biometryType?: BiometryType | (string & {});\n error?: string;\n}\nexport interface BiometricRequest {\n /** Text shown in the operating system authentication prompt (1–200 characters). */\n reason: string;\n cancelButtonText?: string;\n}\n\n/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */\nexport const getBiometricAvailability = (): Promise<BiometricAvailability> =>\n call<BiometricAvailability>('getBiometricAvailability');\n\n/** Kết quả nguyên bản của react-native-biometrics.simplePrompt(). */\nexport interface BiometricResult {\n success: boolean;\n error?: string;\n}\n\n/** Trả nguyên kết quả native, kể cả success: false khi huỷ. Native reject vẫn được chuyển thành lỗi bridge. */\nexport const authenticateBiometric = (request: BiometricRequest): Promise<BiometricResult> =>\n call<BiometricResult>('authenticateBiometric', request, 10 * 60 * 1000);\n","import { call, on } from '../bridge';\n\nexport interface SpeechOptions {\n /** Ngôn ngữ nhận dạng, mặc định vi-VN. */\n lang?: string;\n continuous?: boolean;\n interimResults?: boolean;\n addsPunctuation?: boolean;\n requiresOnDeviceRecognition?: boolean;\n}\nexport interface SpeechResult {\n text: string;\n isFinal: boolean;\n results: { transcript: string; confidence: number; [key: string]: unknown }[];\n}\nexport interface SpeechError { code: string; error: string; message: string; }\nexport interface SpeechEvents {\n 'speech.partial': SpeechResult;\n 'speech.final': SpeechResult;\n 'speech.error': SpeechError;\n 'speech.end': undefined;\n}\n\n/** Xin quyền và bắt đầu nghe. Đăng ký event trước khi gọi. Resolve không có nghĩa đã có câu cuối. */\nexport const startSpeech = (options: SpeechOptions = {}): Promise<void> => call<void>('speech.start', options, 120_000);\n/** Yêu cầu dừng; tiếp tục nhận kết quả cuối và speech.end. */\nexport const stopSpeech = (): Promise<void> => call<void>('speech.stop');\n/** Nhận kết quả tạm thời/cuối cùng, lỗi và kết thúc phiên. Trả hàm huỷ đăng ký. */\nexport const onSpeech = <E extends keyof SpeechEvents>(event: E, listener: (data: SpeechEvents[E]) => void): (() => void) =>\n on(event, data => listener(data as SpeechEvents[E]));\n","import { getState } from './bridge';\nimport { notifyReady } from './apis/app';\n\nexport { getRouteParams, onContextChange } from './apis/route';\nexport { getAccessToken, getToken, type TokenType } from './apis/user';\nexport { closeApp, onAppPaused, onAppResumed } from './apis/app';\nexport {\n haptic,\n HapticType,\n openLink,\n openScreen,\n printImage,\n requestPayment,\n type OpenScreenRequest,\n type PaymentRequest,\n type PaymentResult,\n type PrintImageRequest,\n} from './apis/native';\nexport { isInHost } from './bridge';\nexport { MiniAppError, ErrorCode } from './errors';\nexport { SDK_VERSION } from './version';\nexport type { RouteParams } from './types';\n\n// Khởi tạo bridge ngay khi import (host có thể đẩy context trước khi app gọi hàm nào),\n// rồi báo \"ready\" khi DOM sẵn sàng.\nif (typeof window !== 'undefined') {\n getState();\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', notifyReady, { once: true });\n } else {\n queueMicrotask(notifyReady);\n }\n}\n\nexport { getBiometricAvailability, authenticateBiometric, type BiometryType, type BiometricAvailability, type BiometricRequest, type BiometricResult } from './apis/biometrics';\n\nexport { startSpeech, stopSpeech, onSpeech, type SpeechOptions, type SpeechResult, type SpeechError, type SpeechEvents } from './apis/speech';\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -246,7 +246,8 @@ declare const SDK_VERSION: string;
|
|
|
246
246
|
type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';
|
|
247
247
|
interface BiometricAvailability {
|
|
248
248
|
available: boolean;
|
|
249
|
-
biometryType?: BiometryType;
|
|
249
|
+
biometryType?: BiometryType | (string & {});
|
|
250
|
+
error?: string;
|
|
250
251
|
}
|
|
251
252
|
interface BiometricRequest {
|
|
252
253
|
/** Text shown in the operating system authentication prompt (1–200 characters). */
|
|
@@ -255,9 +256,47 @@ interface BiometricRequest {
|
|
|
255
256
|
}
|
|
256
257
|
/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */
|
|
257
258
|
declare const getBiometricAvailability: () => Promise<BiometricAvailability>;
|
|
258
|
-
/**
|
|
259
|
-
|
|
260
|
-
success:
|
|
261
|
-
|
|
259
|
+
/** Kết quả nguyên bản của react-native-biometrics.simplePrompt(). */
|
|
260
|
+
interface BiometricResult {
|
|
261
|
+
success: boolean;
|
|
262
|
+
error?: string;
|
|
263
|
+
}
|
|
264
|
+
/** Trả nguyên kết quả native, kể cả success: false khi huỷ. Native reject vẫn được chuyển thành lỗi bridge. */
|
|
265
|
+
declare const authenticateBiometric: (request: BiometricRequest) => Promise<BiometricResult>;
|
|
266
|
+
|
|
267
|
+
interface SpeechOptions {
|
|
268
|
+
/** Ngôn ngữ nhận dạng, mặc định vi-VN. */
|
|
269
|
+
lang?: string;
|
|
270
|
+
continuous?: boolean;
|
|
271
|
+
interimResults?: boolean;
|
|
272
|
+
addsPunctuation?: boolean;
|
|
273
|
+
requiresOnDeviceRecognition?: boolean;
|
|
274
|
+
}
|
|
275
|
+
interface SpeechResult {
|
|
276
|
+
text: string;
|
|
277
|
+
isFinal: boolean;
|
|
278
|
+
results: {
|
|
279
|
+
transcript: string;
|
|
280
|
+
confidence: number;
|
|
281
|
+
[key: string]: unknown;
|
|
282
|
+
}[];
|
|
283
|
+
}
|
|
284
|
+
interface SpeechError {
|
|
285
|
+
code: string;
|
|
286
|
+
error: string;
|
|
287
|
+
message: string;
|
|
288
|
+
}
|
|
289
|
+
interface SpeechEvents {
|
|
290
|
+
'speech.partial': SpeechResult;
|
|
291
|
+
'speech.final': SpeechResult;
|
|
292
|
+
'speech.error': SpeechError;
|
|
293
|
+
'speech.end': undefined;
|
|
294
|
+
}
|
|
295
|
+
/** Xin quyền và bắt đầu nghe. Đăng ký event trước khi gọi. Resolve không có nghĩa đã có câu cuối. */
|
|
296
|
+
declare const startSpeech: (options?: SpeechOptions) => Promise<void>;
|
|
297
|
+
/** Yêu cầu dừng; tiếp tục nhận kết quả cuối và speech.end. */
|
|
298
|
+
declare const stopSpeech: () => Promise<void>;
|
|
299
|
+
/** Nhận kết quả tạm thời/cuối cùng, lỗi và kết thúc phiên. Trả hàm huỷ đăng ký. */
|
|
300
|
+
declare const onSpeech: <E extends keyof SpeechEvents>(event: E, listener: (data: SpeechEvents[E]) => void) => (() => void);
|
|
262
301
|
|
|
263
|
-
export { type BiometricAvailability, type BiometricRequest, type BiometryType, ErrorCode, HapticType, MiniAppError, type OpenScreenRequest, type PaymentRequest, type PaymentResult, type PrintImageRequest, type RouteParams, SDK_VERSION, type TokenType, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, openLink, openScreen, printImage, requestPayment };
|
|
302
|
+
export { type BiometricAvailability, type BiometricRequest, type BiometricResult, type BiometryType, ErrorCode, HapticType, MiniAppError, type OpenScreenRequest, type PaymentRequest, type PaymentResult, type PrintImageRequest, type RouteParams, SDK_VERSION, type SpeechError, type SpeechEvents, type SpeechOptions, type SpeechResult, type TokenType, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, onSpeech, openLink, openScreen, printImage, requestPayment, startSpeech, stopSpeech };
|
package/dist/index.d.ts
CHANGED
|
@@ -246,7 +246,8 @@ declare const SDK_VERSION: string;
|
|
|
246
246
|
type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';
|
|
247
247
|
interface BiometricAvailability {
|
|
248
248
|
available: boolean;
|
|
249
|
-
biometryType?: BiometryType;
|
|
249
|
+
biometryType?: BiometryType | (string & {});
|
|
250
|
+
error?: string;
|
|
250
251
|
}
|
|
251
252
|
interface BiometricRequest {
|
|
252
253
|
/** Text shown in the operating system authentication prompt (1–200 characters). */
|
|
@@ -255,9 +256,47 @@ interface BiometricRequest {
|
|
|
255
256
|
}
|
|
256
257
|
/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */
|
|
257
258
|
declare const getBiometricAvailability: () => Promise<BiometricAvailability>;
|
|
258
|
-
/**
|
|
259
|
-
|
|
260
|
-
success:
|
|
261
|
-
|
|
259
|
+
/** Kết quả nguyên bản của react-native-biometrics.simplePrompt(). */
|
|
260
|
+
interface BiometricResult {
|
|
261
|
+
success: boolean;
|
|
262
|
+
error?: string;
|
|
263
|
+
}
|
|
264
|
+
/** Trả nguyên kết quả native, kể cả success: false khi huỷ. Native reject vẫn được chuyển thành lỗi bridge. */
|
|
265
|
+
declare const authenticateBiometric: (request: BiometricRequest) => Promise<BiometricResult>;
|
|
266
|
+
|
|
267
|
+
interface SpeechOptions {
|
|
268
|
+
/** Ngôn ngữ nhận dạng, mặc định vi-VN. */
|
|
269
|
+
lang?: string;
|
|
270
|
+
continuous?: boolean;
|
|
271
|
+
interimResults?: boolean;
|
|
272
|
+
addsPunctuation?: boolean;
|
|
273
|
+
requiresOnDeviceRecognition?: boolean;
|
|
274
|
+
}
|
|
275
|
+
interface SpeechResult {
|
|
276
|
+
text: string;
|
|
277
|
+
isFinal: boolean;
|
|
278
|
+
results: {
|
|
279
|
+
transcript: string;
|
|
280
|
+
confidence: number;
|
|
281
|
+
[key: string]: unknown;
|
|
282
|
+
}[];
|
|
283
|
+
}
|
|
284
|
+
interface SpeechError {
|
|
285
|
+
code: string;
|
|
286
|
+
error: string;
|
|
287
|
+
message: string;
|
|
288
|
+
}
|
|
289
|
+
interface SpeechEvents {
|
|
290
|
+
'speech.partial': SpeechResult;
|
|
291
|
+
'speech.final': SpeechResult;
|
|
292
|
+
'speech.error': SpeechError;
|
|
293
|
+
'speech.end': undefined;
|
|
294
|
+
}
|
|
295
|
+
/** Xin quyền và bắt đầu nghe. Đăng ký event trước khi gọi. Resolve không có nghĩa đã có câu cuối. */
|
|
296
|
+
declare const startSpeech: (options?: SpeechOptions) => Promise<void>;
|
|
297
|
+
/** Yêu cầu dừng; tiếp tục nhận kết quả cuối và speech.end. */
|
|
298
|
+
declare const stopSpeech: () => Promise<void>;
|
|
299
|
+
/** Nhận kết quả tạm thời/cuối cùng, lỗi và kết thúc phiên. Trả hàm huỷ đăng ký. */
|
|
300
|
+
declare const onSpeech: <E extends keyof SpeechEvents>(event: E, listener: (data: SpeechEvents[E]) => void) => (() => void);
|
|
262
301
|
|
|
263
|
-
export { type BiometricAvailability, type BiometricRequest, type BiometryType, ErrorCode, HapticType, MiniAppError, type OpenScreenRequest, type PaymentRequest, type PaymentResult, type PrintImageRequest, type RouteParams, SDK_VERSION, type TokenType, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, openLink, openScreen, printImage, requestPayment };
|
|
302
|
+
export { type BiometricAvailability, type BiometricRequest, type BiometricResult, type BiometryType, ErrorCode, HapticType, MiniAppError, type OpenScreenRequest, type PaymentRequest, type PaymentResult, type PrintImageRequest, type RouteParams, SDK_VERSION, type SpeechError, type SpeechEvents, type SpeechOptions, type SpeechResult, type TokenType, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, onSpeech, openLink, openScreen, printImage, requestPayment, startSpeech, stopSpeech };
|
package/dist/index.js
CHANGED
|
@@ -155,7 +155,7 @@ var on = (event, listener) => {
|
|
|
155
155
|
};
|
|
156
156
|
|
|
157
157
|
// src/version.ts
|
|
158
|
-
var SDK_VERSION = "0.
|
|
158
|
+
var SDK_VERSION = "0.8.1" ;
|
|
159
159
|
|
|
160
160
|
// src/apis/app.ts
|
|
161
161
|
var closeApp = () => call("closeApp");
|
|
@@ -230,6 +230,11 @@ var haptic = (type = HapticType.selection) => notify("haptic", { type });
|
|
|
230
230
|
var getBiometricAvailability = () => call("getBiometricAvailability");
|
|
231
231
|
var authenticateBiometric = (request) => call("authenticateBiometric", request, 10 * 60 * 1e3);
|
|
232
232
|
|
|
233
|
+
// src/apis/speech.ts
|
|
234
|
+
var startSpeech = (options = {}) => call("speech.start", options, 12e4);
|
|
235
|
+
var stopSpeech = () => call("speech.stop");
|
|
236
|
+
var onSpeech = (event, listener) => on(event, (data) => listener(data));
|
|
237
|
+
|
|
233
238
|
// src/index.ts
|
|
234
239
|
if (typeof window !== "undefined") {
|
|
235
240
|
getState();
|
|
@@ -240,6 +245,6 @@ if (typeof window !== "undefined") {
|
|
|
240
245
|
}
|
|
241
246
|
}
|
|
242
247
|
|
|
243
|
-
export { ErrorCode, HapticType, MiniAppError, SDK_VERSION, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, openLink, openScreen, printImage, requestPayment };
|
|
248
|
+
export { ErrorCode, HapticType, MiniAppError, SDK_VERSION, authenticateBiometric, closeApp, getAccessToken, getBiometricAvailability, getRouteParams, getToken, haptic, isInHost, onAppPaused, onAppResumed, onContextChange, onSpeech, openLink, openScreen, printImage, requestPayment, startSpeech, stopSpeech };
|
|
244
249
|
//# sourceMappingURL=index.js.map
|
|
245
250
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/bridge.ts","../src/version.ts","../src/apis/app.ts","../src/apis/route.ts","../src/apis/user.ts","../src/apis/native.ts","../src/apis/biometrics.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const ErrorCode = {\n INVALID_PARAMS: 'INVALID_PARAMS',\n BIOMETRIC_UNAVAILABLE: 'BIOMETRIC_UNAVAILABLE',\n AUTHENTICATION_FAILED: 'AUTHENTICATION_FAILED',\n /** Không chạy trong app Retion (trình duyệt / iframe cũ). */\n NOT_IN_HOST: 'NOT_IN_HOST',\n /** Host không phản hồi trong thời gian chờ. */\n TIMEOUT: 'TIMEOUT',\n /** Mini app chưa được admin cấp quyền (vd lấy partner_token / chatbox_token). */\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n /** Host (phiên bản app hiện tại) chưa hỗ trợ API này. */\n NOT_SUPPORTED: 'NOT_SUPPORTED',\n /** Người dùng huỷ thao tác (đóng màn thanh toán, không chọn máy in…). */\n CANCELLED: 'CANCELLED',\n /** Đang có 1 lượt cùng loại chạy (vd đang thanh toán mà gọi requestPayment lần nữa). */\n BUSY: 'BUSY',\n /** Lỗi khác phía host. */\n HOST_ERROR: 'HOST_ERROR',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode] | (string & {});\n\nexport class MiniAppError extends Error {\n readonly code: ErrorCode;\n readonly method?: string;\n\n constructor(code: ErrorCode, message: string, method?: string) {\n super(message);\n this.name = 'MiniAppError';\n this.code = code;\n this.method = method;\n }\n\n /** Chuẩn hoá lỗi từ host (object thuần, Error, string) về MiniAppError. */\n static from(error: unknown, method?: string): MiniAppError {\n if (error instanceof MiniAppError) {\n return error;\n }\n if (error && typeof error === 'object') {\n const { code, message } = error as { code?: unknown; message?: unknown };\n return new MiniAppError(\n typeof code === 'string' ? code : ErrorCode.HOST_ERROR,\n typeof message === 'string' ? message : 'Unknown error',\n method,\n );\n }\n return new MiniAppError(ErrorCode.HOST_ERROR, String(error), method);\n }\n}\n","/**\n * Bridge web mini app ↔ host (app Retion). Nội bộ SDK — dev mini app không import trực tiếp.\n *\n * Giao thức v1\n * web → host : ReactNativeWebView.postMessage(JSON.stringify(RequestMessage))\n * host → web : window.__RETION_MINIAPP__.receive(ResponseMessage | EventMessage)\n * host → web event \"context\" → web gọi onContextChange → web → host \"contextApplied\"\n * host inject trước khi trang chạy:\n * window.__RETION_MINIAPP_HOST__ = { protocol } ← đánh dấu host hỗ trợ SDK\n * window.__RETION_MINIAPP_CONTEXT__ = RouteParams ← context ban đầu\n *\n * Chỉ có ReactNativeWebView KHÔNG đủ để coi là host: màn iframe cũ của app cũng là RN WebView\n * nhưng không hiểu giao thức này (gọi API sẽ treo tới timeout). Thiếu marker → NOT_IN_HOST ngay.\n *\n * State đặt trên window (singleton): nhiều bản SDK trong cùng trang (trùng version trong\n * node_modules) vẫn dùng chung 1 bridge thay vì ghi đè hàm receive của nhau.\n */\nimport { ErrorCode, MiniAppError } from './errors';\nimport type { RouteParams } from './types';\n\nexport const PROTOCOL_VERSION = 1;\nexport const DEFAULT_TIMEOUT_MS = 15_000;\nexport const CONTEXT_EVENT = 'context';\n/** web → host: đã áp dụng context mới (sau khi gọi các listener onContextChange). */\nexport const CONTEXT_APPLIED = 'contextApplied';\n\nexport interface RequestMessage {\n __retion: typeof PROTOCOL_VERSION;\n /** Có id → host phải trả ResponseMessage. Không có → lệnh 1 chiều. */\n id?: string;\n method: string;\n params?: unknown;\n}\n\nexport type ResponseMessage =\n | { id: string; result?: unknown; error?: undefined }\n | { id: string; error: { code: string; message: string } };\n\nexport interface EventMessage {\n event: string;\n data?: unknown;\n}\n\nexport interface HostInfo {\n /** Phiên bản giao thức host hỗ trợ. */\n protocol: number;\n}\n\ntype Listener = (data: unknown) => void;\n\ninterface Pending {\n method: string;\n resolve: (value: unknown) => void;\n reject: (error: MiniAppError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface BridgeState {\n protocol: number;\n seq: number;\n pending: Map<string, Pending>;\n listeners: Map<string, Set<Listener>>;\n context: RouteParams;\n receive: (message: ResponseMessage | EventMessage) => void;\n}\n\ndeclare global {\n interface Window {\n ReactNativeWebView?: { postMessage: (message: string) => void };\n __RETION_MINIAPP__?: BridgeState;\n __RETION_MINIAPP_CONTEXT__?: RouteParams;\n __RETION_MINIAPP_HOST__?: HostInfo;\n }\n}\n\nconst hasWindow = typeof window !== 'undefined';\n\nconst readInitialContext = (): RouteParams => {\n if (!hasWindow) {\n return {};\n }\n const query = Object.fromEntries(new URLSearchParams(window.location.search));\n return { ...query, ...(window.__RETION_MINIAPP_CONTEXT__ ?? {}) };\n};\n\nconst createState = (): BridgeState => {\n const state: BridgeState = {\n protocol: PROTOCOL_VERSION,\n seq: 0,\n pending: new Map(),\n listeners: new Map(),\n context: readInitialContext(),\n receive: (message) => {\n if (!message || typeof message !== 'object') {\n return;\n }\n if ('event' in message) {\n if (message.event === CONTEXT_EVENT) {\n // Cập nhật context TRƯỚC khi emit → getRouteParams() luôn đúng, kể cả không ai lắng nghe.\n const prev = state.context;\n // Host luôn gửi ĐỦ context của lần mở → thay hẳn, không gộp với context cũ: gộp thì param\n // lần trước không còn (vd. message_id khi mở từ nút CTA rồi mở lại từ menu) vẫn bị giữ lại.\n const next = { ...(message.data as RouteParams) };\n // Host đẩy lại context lúc \"ready\" dù không đổi → không báo onContextChange thừa.\n if (JSON.stringify(next) !== JSON.stringify(prev)) {\n state.context = next;\n emit(state, CONTEXT_EVENT, { next: { ...next }, prev });\n }\n // Báo host: web đã nhận context (listener đã chạy) → host bỏ lớp che nội dung page cũ.\n notify(CONTEXT_APPLIED);\n return;\n }\n emit(state, message.event, message.data);\n return;\n }\n const pending = state.pending.get(message.id);\n if (!pending) {\n return;\n }\n state.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.reject(MiniAppError.from(message.error, pending.method));\n } else {\n pending.resolve(message.result);\n }\n },\n };\n return state;\n};\n\nconst emit = (state: BridgeState, event: string, data: unknown) => {\n state.listeners.get(event)?.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`[retion-miniapp] listener \"${event}\" lỗi`, error);\n }\n });\n};\n\nlet fallback_state: BridgeState | null = null;\n\n/** @internal */\nexport const getState = (): BridgeState => {\n if (!hasWindow) {\n return (fallback_state ??= createState());\n }\n return (window.__RETION_MINIAPP__ ??= createState());\n};\n\n/** Đang chạy trong app Retion có hỗ trợ SDK (host đã inject marker + kênh postMessage). */\nexport const isInHost = (): boolean =>\n hasWindow &&\n typeof window.__RETION_MINIAPP_HOST__?.protocol === 'number' &&\n typeof window.ReactNativeWebView?.postMessage === 'function';\n\nconst post = (message: RequestMessage) => {\n window.ReactNativeWebView!.postMessage(JSON.stringify(message));\n};\n\n/** Gửi lệnh lên host và chờ kết quả. Ngoài app → reject NOT_IN_HOST. */\nexport const call = <T>(method: string, params?: unknown, timeout_ms = DEFAULT_TIMEOUT_MS): Promise<T> => {\n const state = getState();\n\n if (!isInHost()) {\n return Promise.reject(new MiniAppError(ErrorCode.NOT_IN_HOST, `${method} chỉ chạy trong app Retion`, method));\n }\n\n const id = `${Date.now().toString(36)}-${++state.seq}`;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id);\n reject(new MiniAppError(ErrorCode.TIMEOUT, `${method}: host không phản hồi sau ${timeout_ms}ms`, method));\n }, timeout_ms);\n state.pending.set(id, { method, resolve: resolve as (v: unknown) => void, reject, timer });\n post({ __retion: PROTOCOL_VERSION, id, method, params });\n });\n};\n\n/** Lệnh 1 chiều (không chờ kết quả). Ngoài app: bỏ qua. */\nexport const notify = (method: string, params?: unknown): void => {\n if (isInHost()) {\n post({ __retion: PROTOCOL_VERSION, method, params });\n }\n};\n\n/** Lắng nghe event host đẩy xuống. Trả về hàm huỷ. */\nexport const on = (event: string, listener: Listener): (() => void) => {\n const { listeners } = getState();\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n};\n","declare const __SDK_VERSION__: string;\n\n/** Thay lúc build (tsup define) / test (vitest define) bằng version trong package.json. */\nexport const SDK_VERSION: string = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n","import { call, notify, on } from '../bridge';\nimport { SDK_VERSION } from '../version';\n\n/**\n * Đóng mini app, quay về màn chat. Ngoài app → reject NOT_IN_HOST (web tự xử lý, vd router.back()).\n */\nexport const closeApp = (): Promise<void> => call<void>('closeApp');\n\n/** @internal SDK tự gọi khi trang sẵn sàng — host ẩn splash + đẩy context mới nhất. */\nexport const notifyReady = (): void => notify('ready', { sdkVersion: SDK_VERSION });\n\n/**\n * Mini app bị đóng (ẩn, vẫn chạy ngầm) — dừng polling / timer / video ở đây cho đỡ tốn pin.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppPaused = (listener: () => void): (() => void) => on('paused', () => listener());\n\n/**\n * Mini app được mở lại (trang vẫn giữ nguyên) — làm mới dữ liệu nếu cần.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppResumed = (listener: () => void): (() => void) => on('resumed', () => listener());\n","import { CONTEXT_EVENT, getState, on } from '../bridge';\nimport type { RouteParams } from '../types';\n\n/**\n * Thông tin conversation lúc mở mini app (đồng bộ, gọi bất cứ lúc nào).\n * @example\n * const { page_id, client_id } = getRouteParams();\n */\nexport const getRouteParams = (): RouteParams => ({ ...getState().context });\n\n/**\n * Mini app đang mở sẵn được mở lại ở conversation khác (khác page / khách, cùng tổ chức).\n * App không nạp lại trang → gọi lại API theo thông tin mới ở đây. Đổi tổ chức thì app nạp lại trang.\n * @returns hàm huỷ lắng nghe\n * @example\n * onContextChange(({ page_id, client_id }) => loadData(page_id, client_id));\n */\nexport const onContextChange = (listener: (next: RouteParams, prev: RouteParams) => void): (() => void) =>\n on(CONTEXT_EVENT, (data) => {\n const { next, prev } = data as { next: RouteParams; prev: RouteParams };\n listener(next, prev);\n });\n","import { call, isInHost } from '../bridge';\nimport { ErrorCode, MiniAppError } from '../errors';\n\n/** Tên query param chứa token khi chạy ngoài app (giống URL iframe hiện tại). */\nconst TOKEN_QUERY_PARAM = 'access_token';\n\nconst readTokenFromUrl = (): string | null => {\n if (typeof window === 'undefined') {\n return null;\n }\n return new URLSearchParams(window.location.search).get(TOKEN_QUERY_PARAM);\n};\n\n/**\n * Token để mini app gọi API backend của chính mình (Authorization: Bearer ...).\n * - Trong app: lấy từ host, luôn là token của page hiện tại, host tự refresh.\n * - Ngoài app: đọc `?access_token=` trên URL (như iframe hiện tại).\n * Gọi lại mỗi khi cần — không lưu token lâu phía web.\n */\nexport const getAccessToken = async (): Promise<string> => {\n if (isInHost()) {\n return call<string>('getAccessToken');\n }\n const token = readTokenFromUrl();\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${TOKEN_QUERY_PARAM}= trên URL`, 'getAccessToken');\n }\n return token;\n};\n\n/** Loại token: `access` luôn được phép; `partner` / `chatbox` cần admin bật quyền trên Console. */\nexport type TokenType = 'access' | 'partner' | 'chatbox';\n\n/** Tên query param tương ứng khi chạy ngoài app (giống URL iframe hiện tại). */\nconst QUERY_PARAM: Record<TokenType, string> = {\n access: 'access_token',\n partner: 'partner_token',\n chatbox: 'chatbox_token',\n};\n\n/**\n * Lấy token theo loại.\n * - `access`: token của mini app cho page hiện tại (= getAccessToken()).\n * - `partner`: token đối tác của page — cần quyền `partner_token`.\n * - `chatbox`: token đăng nhập của người dùng app (toàn quyền) — cần quyền `chatbox_token`.\n * Trong app, chưa được cấp quyền → MiniAppError PERMISSION_DENIED. Ngoài app: đọc query URL.\n */\nexport const getToken = async (type: TokenType): Promise<string> => {\n if (!(type in QUERY_PARAM)) {\n throw new MiniAppError(ErrorCode.HOST_ERROR, `Loại token không hợp lệ: ${String(type)}`, 'getToken');\n }\n if (isInHost()) {\n return call<string>('getToken', { type });\n }\n const token = typeof window === 'undefined' ? null : new URLSearchParams(window.location.search).get(QUERY_PARAM[type]);\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${QUERY_PARAM[type]}= trên URL`, 'getToken');\n }\n return token;\n};\n","import { call, notify } from '../bridge';\n\n/**\n * Chức năng native do app cung cấp (thanh toán, in, mở màn hình của app).\n * Mỗi app tự cài phần xử lý — app không hỗ trợ → MiniAppError NOT_SUPPORTED (web ẩn nút / báo người dùng).\n * Người dùng huỷ (đóng màn thanh toán, không chọn máy in…) → MiniAppError CANCELLED.\n * Đang thanh toán / in mà gọi lần nữa (bấm 2 lần) → MiniAppError BUSY — lượt đầu vẫn chạy bình thường.\n */\n\n/** Chờ người dùng thao tác (chạm thẻ, chọn máy in) — lâu hơn timeout mặc định 15s. */\nconst USER_ACTION_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport interface PaymentRequest {\n /** Số tiền theo đơn vị tiền tệ (vd 12.5 = 12,50 CAD). */\n amount: number;\n /** Mã tiền tệ ISO 4217: CAD, USD, VND… */\n currency: string;\n /** Mã đơn của bạn — app gắn vào giao dịch để đối soát. */\n order_id?: string;\n /** Ghi chú hiện trên giao dịch. */\n note?: string;\n /** Dữ liệu thêm app cần (vd chi tiết đơn) — tuỳ app. */\n metadata?: Record<string, unknown>;\n}\n\nexport interface PaymentResult {\n /** Mã giao dịch phía cổng thanh toán. */\n transaction_id: string;\n /** Cổng thanh toán: SQUARE, STRIPE, VNPAY… */\n provider: string;\n [key: string]: unknown;\n}\n\n/**\n * Thanh toán qua cổng của app (vd Tap to Pay). Resolve khi thanh toán thành công.\n * Luôn đối soát lại qua backend theo `order_id`: web có thể đóng / hết thời gian chờ trong khi giao dịch\n * phía app vẫn thành công.\n * @example\n * const { transaction_id, provider } = await requestPayment({ amount: 12.5, currency: 'CAD', order_id });\n */\nexport const requestPayment = (request: PaymentRequest): Promise<PaymentResult> =>\n call<PaymentResult>('requestPayment', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface PrintImageRequest {\n /** Ảnh hoá đơn base64 — có hoặc không có tiền tố `data:image/png;base64,`. */\n image: string;\n}\n\n/**\n * In ảnh (hoá đơn) ra máy in của app. App tự hiện chọn máy in nếu cần. Resolve khi in xong.\n */\nexport const printImage = (request: PrintImageRequest): Promise<void> =>\n call<void>('printImage', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface OpenScreenRequest {\n /** Tên màn hình app định nghĩa (vd `conversation`, `customer`) — xem tài liệu của app. */\n screen: string;\n params?: Record<string, unknown>;\n}\n\n/**\n * Mở 1 màn hình của app (app đóng mini app rồi chuyển màn). Màn không tồn tại → NOT_SUPPORTED.\n * @example\n * await openScreen({ screen: 'customer', params: { customer_id } });\n */\nexport const openScreen = (request: OpenScreenRequest): Promise<void> =>\n call<void>('openScreen', request);\n\n/**\n * Mở link bằng hệ điều hành — deeplink sang app khác (retion://…), tel:, mailto:, https (trình duyệt ngoài).\n * Không ứng dụng nào mở được (chưa cài app đích) / app chưa hỗ trợ → NOT_SUPPORTED (web tự mở link dự phòng).\n * @example\n * await openLink('retion://chat').catch(() => window.open(store_url, '_blank'));\n */\nexport const openLink = (url: string): Promise<void> => call<void>('openLink', { url });\n\n/**\n * Kiểu rung phản hồi — tên y hệt react-native-haptic-feedback: `haptic(HapticType.notificationSuccess)`.\n * - selection: đổi lựa chọn (tab, picker, toggle)\n * - impactLight / impactMedium / impactHeavy / rigid / soft: va chạm (bấm nút, kéo thả)\n * - notificationSuccess / notificationWarning / notificationError: kết quả thao tác\n */\nexport const HapticType = {\n selection: 'selection',\n impactLight: 'impactLight',\n impactMedium: 'impactMedium',\n impactHeavy: 'impactHeavy',\n rigid: 'rigid',\n soft: 'soft',\n notificationSuccess: 'notificationSuccess',\n notificationWarning: 'notificationWarning',\n notificationError: 'notificationError',\n} as const;\n\nexport type HapticType = (typeof HapticType)[keyof typeof HapticType];\n\n/**\n * Rung phản hồi — gọi lúc nào cũng được, không chờ kết quả. Ngoài app / app chưa hỗ trợ → bỏ qua.\n * @example\n * haptic(HapticType.impactLight); // bấm nút\n * await requestPayment(request); haptic(HapticType.notificationSuccess);\n */\nexport const haptic = (type: HapticType = HapticType.selection): void => notify('haptic', { type });\n","import { call } from '../bridge';\n\nexport type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';\nexport interface BiometricAvailability {\n available: boolean;\n biometryType?: BiometryType;\n}\nexport interface BiometricRequest {\n /** Text shown in the operating system authentication prompt (1–200 characters). */\n reason: string;\n cancelButtonText?: string;\n}\n\n/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */\nexport const getBiometricAvailability = (): Promise<BiometricAvailability> =>\n call<BiometricAvailability>('getBiometricAvailability');\n\n/** Local verification only. Rejects on cancellation/failure; never returns biometric data or a login token. */\nexport const authenticateBiometric = (request: BiometricRequest): Promise<{ success: true }> =>\n call<{ success: true }>('authenticateBiometric', request, 10 * 60 * 1000);\n","import { getState } from './bridge';\nimport { notifyReady } from './apis/app';\n\nexport { getRouteParams, onContextChange } from './apis/route';\nexport { getAccessToken, getToken, type TokenType } from './apis/user';\nexport { closeApp, onAppPaused, onAppResumed } from './apis/app';\nexport {\n haptic,\n HapticType,\n openLink,\n openScreen,\n printImage,\n requestPayment,\n type OpenScreenRequest,\n type PaymentRequest,\n type PaymentResult,\n type PrintImageRequest,\n} from './apis/native';\nexport { isInHost } from './bridge';\nexport { MiniAppError, ErrorCode } from './errors';\nexport { SDK_VERSION } from './version';\nexport type { RouteParams } from './types';\n\n// Khởi tạo bridge ngay khi import (host có thể đẩy context trước khi app gọi hàm nào),\n// rồi báo \"ready\" khi DOM sẵn sàng.\nif (typeof window !== 'undefined') {\n getState();\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', notifyReady, { once: true });\n } else {\n queueMicrotask(notifyReady);\n }\n}\n\nexport { getBiometricAvailability, authenticateBiometric, type BiometryType, type BiometricAvailability, type BiometricRequest } from './apis/biometrics';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/bridge.ts","../src/version.ts","../src/apis/app.ts","../src/apis/route.ts","../src/apis/user.ts","../src/apis/native.ts","../src/apis/biometrics.ts","../src/apis/speech.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export const ErrorCode = {\n INVALID_PARAMS: 'INVALID_PARAMS',\n BIOMETRIC_UNAVAILABLE: 'BIOMETRIC_UNAVAILABLE',\n AUTHENTICATION_FAILED: 'AUTHENTICATION_FAILED',\n /** Không chạy trong app Retion (trình duyệt / iframe cũ). */\n NOT_IN_HOST: 'NOT_IN_HOST',\n /** Host không phản hồi trong thời gian chờ. */\n TIMEOUT: 'TIMEOUT',\n /** Mini app chưa được admin cấp quyền (vd lấy partner_token / chatbox_token). */\n PERMISSION_DENIED: 'PERMISSION_DENIED',\n /** Host (phiên bản app hiện tại) chưa hỗ trợ API này. */\n NOT_SUPPORTED: 'NOT_SUPPORTED',\n /** Người dùng huỷ thao tác (đóng màn thanh toán, không chọn máy in…). */\n CANCELLED: 'CANCELLED',\n /** Đang có 1 lượt cùng loại chạy (vd đang thanh toán mà gọi requestPayment lần nữa). */\n BUSY: 'BUSY',\n /** Lỗi khác phía host. */\n HOST_ERROR: 'HOST_ERROR',\n} as const;\n\nexport type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode] | (string & {});\n\nexport class MiniAppError extends Error {\n readonly code: ErrorCode;\n readonly method?: string;\n\n constructor(code: ErrorCode, message: string, method?: string) {\n super(message);\n this.name = 'MiniAppError';\n this.code = code;\n this.method = method;\n }\n\n /** Chuẩn hoá lỗi từ host (object thuần, Error, string) về MiniAppError. */\n static from(error: unknown, method?: string): MiniAppError {\n if (error instanceof MiniAppError) {\n return error;\n }\n if (error && typeof error === 'object') {\n const { code, message } = error as { code?: unknown; message?: unknown };\n return new MiniAppError(\n typeof code === 'string' ? code : ErrorCode.HOST_ERROR,\n typeof message === 'string' ? message : 'Unknown error',\n method,\n );\n }\n return new MiniAppError(ErrorCode.HOST_ERROR, String(error), method);\n }\n}\n","/**\n * Bridge web mini app ↔ host (app Retion). Nội bộ SDK — dev mini app không import trực tiếp.\n *\n * Giao thức v1\n * web → host : ReactNativeWebView.postMessage(JSON.stringify(RequestMessage))\n * host → web : window.__RETION_MINIAPP__.receive(ResponseMessage | EventMessage)\n * host → web event \"context\" → web gọi onContextChange → web → host \"contextApplied\"\n * host inject trước khi trang chạy:\n * window.__RETION_MINIAPP_HOST__ = { protocol } ← đánh dấu host hỗ trợ SDK\n * window.__RETION_MINIAPP_CONTEXT__ = RouteParams ← context ban đầu\n *\n * Chỉ có ReactNativeWebView KHÔNG đủ để coi là host: màn iframe cũ của app cũng là RN WebView\n * nhưng không hiểu giao thức này (gọi API sẽ treo tới timeout). Thiếu marker → NOT_IN_HOST ngay.\n *\n * State đặt trên window (singleton): nhiều bản SDK trong cùng trang (trùng version trong\n * node_modules) vẫn dùng chung 1 bridge thay vì ghi đè hàm receive của nhau.\n */\nimport { ErrorCode, MiniAppError } from './errors';\nimport type { RouteParams } from './types';\n\nexport const PROTOCOL_VERSION = 1;\nexport const DEFAULT_TIMEOUT_MS = 15_000;\nexport const CONTEXT_EVENT = 'context';\n/** web → host: đã áp dụng context mới (sau khi gọi các listener onContextChange). */\nexport const CONTEXT_APPLIED = 'contextApplied';\n\nexport interface RequestMessage {\n __retion: typeof PROTOCOL_VERSION;\n /** Có id → host phải trả ResponseMessage. Không có → lệnh 1 chiều. */\n id?: string;\n method: string;\n params?: unknown;\n}\n\nexport type ResponseMessage =\n | { id: string; result?: unknown; error?: undefined }\n | { id: string; error: { code: string; message: string } };\n\nexport interface EventMessage {\n event: string;\n data?: unknown;\n}\n\nexport interface HostInfo {\n /** Phiên bản giao thức host hỗ trợ. */\n protocol: number;\n}\n\ntype Listener = (data: unknown) => void;\n\ninterface Pending {\n method: string;\n resolve: (value: unknown) => void;\n reject: (error: MiniAppError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface BridgeState {\n protocol: number;\n seq: number;\n pending: Map<string, Pending>;\n listeners: Map<string, Set<Listener>>;\n context: RouteParams;\n receive: (message: ResponseMessage | EventMessage) => void;\n}\n\ndeclare global {\n interface Window {\n ReactNativeWebView?: { postMessage: (message: string) => void };\n __RETION_MINIAPP__?: BridgeState;\n __RETION_MINIAPP_CONTEXT__?: RouteParams;\n __RETION_MINIAPP_HOST__?: HostInfo;\n }\n}\n\nconst hasWindow = typeof window !== 'undefined';\n\nconst readInitialContext = (): RouteParams => {\n if (!hasWindow) {\n return {};\n }\n const query = Object.fromEntries(new URLSearchParams(window.location.search));\n return { ...query, ...(window.__RETION_MINIAPP_CONTEXT__ ?? {}) };\n};\n\nconst createState = (): BridgeState => {\n const state: BridgeState = {\n protocol: PROTOCOL_VERSION,\n seq: 0,\n pending: new Map(),\n listeners: new Map(),\n context: readInitialContext(),\n receive: (message) => {\n if (!message || typeof message !== 'object') {\n return;\n }\n if ('event' in message) {\n if (message.event === CONTEXT_EVENT) {\n // Cập nhật context TRƯỚC khi emit → getRouteParams() luôn đúng, kể cả không ai lắng nghe.\n const prev = state.context;\n // Host luôn gửi ĐỦ context của lần mở → thay hẳn, không gộp với context cũ: gộp thì param\n // lần trước không còn (vd. message_id khi mở từ nút CTA rồi mở lại từ menu) vẫn bị giữ lại.\n const next = { ...(message.data as RouteParams) };\n // Host đẩy lại context lúc \"ready\" dù không đổi → không báo onContextChange thừa.\n if (JSON.stringify(next) !== JSON.stringify(prev)) {\n state.context = next;\n emit(state, CONTEXT_EVENT, { next: { ...next }, prev });\n }\n // Báo host: web đã nhận context (listener đã chạy) → host bỏ lớp che nội dung page cũ.\n notify(CONTEXT_APPLIED);\n return;\n }\n emit(state, message.event, message.data);\n return;\n }\n const pending = state.pending.get(message.id);\n if (!pending) {\n return;\n }\n state.pending.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.reject(MiniAppError.from(message.error, pending.method));\n } else {\n pending.resolve(message.result);\n }\n },\n };\n return state;\n};\n\nconst emit = (state: BridgeState, event: string, data: unknown) => {\n state.listeners.get(event)?.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`[retion-miniapp] listener \"${event}\" lỗi`, error);\n }\n });\n};\n\nlet fallback_state: BridgeState | null = null;\n\n/** @internal */\nexport const getState = (): BridgeState => {\n if (!hasWindow) {\n return (fallback_state ??= createState());\n }\n return (window.__RETION_MINIAPP__ ??= createState());\n};\n\n/** Đang chạy trong app Retion có hỗ trợ SDK (host đã inject marker + kênh postMessage). */\nexport const isInHost = (): boolean =>\n hasWindow &&\n typeof window.__RETION_MINIAPP_HOST__?.protocol === 'number' &&\n typeof window.ReactNativeWebView?.postMessage === 'function';\n\nconst post = (message: RequestMessage) => {\n window.ReactNativeWebView!.postMessage(JSON.stringify(message));\n};\n\n/** Gửi lệnh lên host và chờ kết quả. Ngoài app → reject NOT_IN_HOST. */\nexport const call = <T>(method: string, params?: unknown, timeout_ms = DEFAULT_TIMEOUT_MS): Promise<T> => {\n const state = getState();\n\n if (!isInHost()) {\n return Promise.reject(new MiniAppError(ErrorCode.NOT_IN_HOST, `${method} chỉ chạy trong app Retion`, method));\n }\n\n const id = `${Date.now().toString(36)}-${++state.seq}`;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n state.pending.delete(id);\n reject(new MiniAppError(ErrorCode.TIMEOUT, `${method}: host không phản hồi sau ${timeout_ms}ms`, method));\n }, timeout_ms);\n state.pending.set(id, { method, resolve: resolve as (v: unknown) => void, reject, timer });\n post({ __retion: PROTOCOL_VERSION, id, method, params });\n });\n};\n\n/** Lệnh 1 chiều (không chờ kết quả). Ngoài app: bỏ qua. */\nexport const notify = (method: string, params?: unknown): void => {\n if (isInHost()) {\n post({ __retion: PROTOCOL_VERSION, method, params });\n }\n};\n\n/** Lắng nghe event host đẩy xuống. Trả về hàm huỷ. */\nexport const on = (event: string, listener: Listener): (() => void) => {\n const { listeners } = getState();\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n set.add(listener);\n return () => {\n set.delete(listener);\n };\n};\n","declare const __SDK_VERSION__: string;\n\n/** Thay lúc build (tsup define) / test (vitest define) bằng version trong package.json. */\nexport const SDK_VERSION: string = typeof __SDK_VERSION__ === 'string' ? __SDK_VERSION__ : '0.0.0-dev';\n","import { call, notify, on } from '../bridge';\nimport { SDK_VERSION } from '../version';\n\n/**\n * Đóng mini app, quay về màn chat. Ngoài app → reject NOT_IN_HOST (web tự xử lý, vd router.back()).\n */\nexport const closeApp = (): Promise<void> => call<void>('closeApp');\n\n/** @internal SDK tự gọi khi trang sẵn sàng — host ẩn splash + đẩy context mới nhất. */\nexport const notifyReady = (): void => notify('ready', { sdkVersion: SDK_VERSION });\n\n/**\n * Mini app bị đóng (ẩn, vẫn chạy ngầm) — dừng polling / timer / video ở đây cho đỡ tốn pin.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppPaused = (listener: () => void): (() => void) => on('paused', () => listener());\n\n/**\n * Mini app được mở lại (trang vẫn giữ nguyên) — làm mới dữ liệu nếu cần.\n * @returns hàm huỷ lắng nghe\n */\nexport const onAppResumed = (listener: () => void): (() => void) => on('resumed', () => listener());\n","import { CONTEXT_EVENT, getState, on } from '../bridge';\nimport type { RouteParams } from '../types';\n\n/**\n * Thông tin conversation lúc mở mini app (đồng bộ, gọi bất cứ lúc nào).\n * @example\n * const { page_id, client_id } = getRouteParams();\n */\nexport const getRouteParams = (): RouteParams => ({ ...getState().context });\n\n/**\n * Mini app đang mở sẵn được mở lại ở conversation khác (khác page / khách, cùng tổ chức).\n * App không nạp lại trang → gọi lại API theo thông tin mới ở đây. Đổi tổ chức thì app nạp lại trang.\n * @returns hàm huỷ lắng nghe\n * @example\n * onContextChange(({ page_id, client_id }) => loadData(page_id, client_id));\n */\nexport const onContextChange = (listener: (next: RouteParams, prev: RouteParams) => void): (() => void) =>\n on(CONTEXT_EVENT, (data) => {\n const { next, prev } = data as { next: RouteParams; prev: RouteParams };\n listener(next, prev);\n });\n","import { call, isInHost } from '../bridge';\nimport { ErrorCode, MiniAppError } from '../errors';\n\n/** Tên query param chứa token khi chạy ngoài app (giống URL iframe hiện tại). */\nconst TOKEN_QUERY_PARAM = 'access_token';\n\nconst readTokenFromUrl = (): string | null => {\n if (typeof window === 'undefined') {\n return null;\n }\n return new URLSearchParams(window.location.search).get(TOKEN_QUERY_PARAM);\n};\n\n/**\n * Token để mini app gọi API backend của chính mình (Authorization: Bearer ...).\n * - Trong app: lấy từ host, luôn là token của page hiện tại, host tự refresh.\n * - Ngoài app: đọc `?access_token=` trên URL (như iframe hiện tại).\n * Gọi lại mỗi khi cần — không lưu token lâu phía web.\n */\nexport const getAccessToken = async (): Promise<string> => {\n if (isInHost()) {\n return call<string>('getAccessToken');\n }\n const token = readTokenFromUrl();\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${TOKEN_QUERY_PARAM}= trên URL`, 'getAccessToken');\n }\n return token;\n};\n\n/** Loại token: `access` luôn được phép; `partner` / `chatbox` cần admin bật quyền trên Console. */\nexport type TokenType = 'access' | 'partner' | 'chatbox';\n\n/** Tên query param tương ứng khi chạy ngoài app (giống URL iframe hiện tại). */\nconst QUERY_PARAM: Record<TokenType, string> = {\n access: 'access_token',\n partner: 'partner_token',\n chatbox: 'chatbox_token',\n};\n\n/**\n * Lấy token theo loại.\n * - `access`: token của mini app cho page hiện tại (= getAccessToken()).\n * - `partner`: token đối tác của page — cần quyền `partner_token`.\n * - `chatbox`: token đăng nhập của người dùng app (toàn quyền) — cần quyền `chatbox_token`.\n * Trong app, chưa được cấp quyền → MiniAppError PERMISSION_DENIED. Ngoài app: đọc query URL.\n */\nexport const getToken = async (type: TokenType): Promise<string> => {\n if (!(type in QUERY_PARAM)) {\n throw new MiniAppError(ErrorCode.HOST_ERROR, `Loại token không hợp lệ: ${String(type)}`, 'getToken');\n }\n if (isInHost()) {\n return call<string>('getToken', { type });\n }\n const token = typeof window === 'undefined' ? null : new URLSearchParams(window.location.search).get(QUERY_PARAM[type]);\n if (!token) {\n throw new MiniAppError(ErrorCode.NOT_IN_HOST, `Ngoài app: thiếu ?${QUERY_PARAM[type]}= trên URL`, 'getToken');\n }\n return token;\n};\n","import { call, notify } from '../bridge';\n\n/**\n * Chức năng native do app cung cấp (thanh toán, in, mở màn hình của app).\n * Mỗi app tự cài phần xử lý — app không hỗ trợ → MiniAppError NOT_SUPPORTED (web ẩn nút / báo người dùng).\n * Người dùng huỷ (đóng màn thanh toán, không chọn máy in…) → MiniAppError CANCELLED.\n * Đang thanh toán / in mà gọi lần nữa (bấm 2 lần) → MiniAppError BUSY — lượt đầu vẫn chạy bình thường.\n */\n\n/** Chờ người dùng thao tác (chạm thẻ, chọn máy in) — lâu hơn timeout mặc định 15s. */\nconst USER_ACTION_TIMEOUT_MS = 10 * 60 * 1000;\n\nexport interface PaymentRequest {\n /** Số tiền theo đơn vị tiền tệ (vd 12.5 = 12,50 CAD). */\n amount: number;\n /** Mã tiền tệ ISO 4217: CAD, USD, VND… */\n currency: string;\n /** Mã đơn của bạn — app gắn vào giao dịch để đối soát. */\n order_id?: string;\n /** Ghi chú hiện trên giao dịch. */\n note?: string;\n /** Dữ liệu thêm app cần (vd chi tiết đơn) — tuỳ app. */\n metadata?: Record<string, unknown>;\n}\n\nexport interface PaymentResult {\n /** Mã giao dịch phía cổng thanh toán. */\n transaction_id: string;\n /** Cổng thanh toán: SQUARE, STRIPE, VNPAY… */\n provider: string;\n [key: string]: unknown;\n}\n\n/**\n * Thanh toán qua cổng của app (vd Tap to Pay). Resolve khi thanh toán thành công.\n * Luôn đối soát lại qua backend theo `order_id`: web có thể đóng / hết thời gian chờ trong khi giao dịch\n * phía app vẫn thành công.\n * @example\n * const { transaction_id, provider } = await requestPayment({ amount: 12.5, currency: 'CAD', order_id });\n */\nexport const requestPayment = (request: PaymentRequest): Promise<PaymentResult> =>\n call<PaymentResult>('requestPayment', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface PrintImageRequest {\n /** Ảnh hoá đơn base64 — có hoặc không có tiền tố `data:image/png;base64,`. */\n image: string;\n}\n\n/**\n * In ảnh (hoá đơn) ra máy in của app. App tự hiện chọn máy in nếu cần. Resolve khi in xong.\n */\nexport const printImage = (request: PrintImageRequest): Promise<void> =>\n call<void>('printImage', request, USER_ACTION_TIMEOUT_MS);\n\nexport interface OpenScreenRequest {\n /** Tên màn hình app định nghĩa (vd `conversation`, `customer`) — xem tài liệu của app. */\n screen: string;\n params?: Record<string, unknown>;\n}\n\n/**\n * Mở 1 màn hình của app (app đóng mini app rồi chuyển màn). Màn không tồn tại → NOT_SUPPORTED.\n * @example\n * await openScreen({ screen: 'customer', params: { customer_id } });\n */\nexport const openScreen = (request: OpenScreenRequest): Promise<void> =>\n call<void>('openScreen', request);\n\n/**\n * Mở link bằng hệ điều hành — deeplink sang app khác (retion://…), tel:, mailto:, https (trình duyệt ngoài).\n * Không ứng dụng nào mở được (chưa cài app đích) / app chưa hỗ trợ → NOT_SUPPORTED (web tự mở link dự phòng).\n * @example\n * await openLink('retion://chat').catch(() => window.open(store_url, '_blank'));\n */\nexport const openLink = (url: string): Promise<void> => call<void>('openLink', { url });\n\n/**\n * Kiểu rung phản hồi — tên y hệt react-native-haptic-feedback: `haptic(HapticType.notificationSuccess)`.\n * - selection: đổi lựa chọn (tab, picker, toggle)\n * - impactLight / impactMedium / impactHeavy / rigid / soft: va chạm (bấm nút, kéo thả)\n * - notificationSuccess / notificationWarning / notificationError: kết quả thao tác\n */\nexport const HapticType = {\n selection: 'selection',\n impactLight: 'impactLight',\n impactMedium: 'impactMedium',\n impactHeavy: 'impactHeavy',\n rigid: 'rigid',\n soft: 'soft',\n notificationSuccess: 'notificationSuccess',\n notificationWarning: 'notificationWarning',\n notificationError: 'notificationError',\n} as const;\n\nexport type HapticType = (typeof HapticType)[keyof typeof HapticType];\n\n/**\n * Rung phản hồi — gọi lúc nào cũng được, không chờ kết quả. Ngoài app / app chưa hỗ trợ → bỏ qua.\n * @example\n * haptic(HapticType.impactLight); // bấm nút\n * await requestPayment(request); haptic(HapticType.notificationSuccess);\n */\nexport const haptic = (type: HapticType = HapticType.selection): void => notify('haptic', { type });\n","import { call } from '../bridge';\n\nexport type BiometryType = 'FaceID' | 'TouchID' | 'Biometrics';\nexport interface BiometricAvailability {\n available: boolean;\n biometryType?: BiometryType | (string & {});\n error?: string;\n}\nexport interface BiometricRequest {\n /** Text shown in the operating system authentication prompt (1–200 characters). */\n reason: string;\n cancelButtonText?: string;\n}\n\n/** Check support/enrollment. An older host may reject with NOT_SUPPORTED. */\nexport const getBiometricAvailability = (): Promise<BiometricAvailability> =>\n call<BiometricAvailability>('getBiometricAvailability');\n\n/** Kết quả nguyên bản của react-native-biometrics.simplePrompt(). */\nexport interface BiometricResult {\n success: boolean;\n error?: string;\n}\n\n/** Trả nguyên kết quả native, kể cả success: false khi huỷ. Native reject vẫn được chuyển thành lỗi bridge. */\nexport const authenticateBiometric = (request: BiometricRequest): Promise<BiometricResult> =>\n call<BiometricResult>('authenticateBiometric', request, 10 * 60 * 1000);\n","import { call, on } from '../bridge';\n\nexport interface SpeechOptions {\n /** Ngôn ngữ nhận dạng, mặc định vi-VN. */\n lang?: string;\n continuous?: boolean;\n interimResults?: boolean;\n addsPunctuation?: boolean;\n requiresOnDeviceRecognition?: boolean;\n}\nexport interface SpeechResult {\n text: string;\n isFinal: boolean;\n results: { transcript: string; confidence: number; [key: string]: unknown }[];\n}\nexport interface SpeechError { code: string; error: string; message: string; }\nexport interface SpeechEvents {\n 'speech.partial': SpeechResult;\n 'speech.final': SpeechResult;\n 'speech.error': SpeechError;\n 'speech.end': undefined;\n}\n\n/** Xin quyền và bắt đầu nghe. Đăng ký event trước khi gọi. Resolve không có nghĩa đã có câu cuối. */\nexport const startSpeech = (options: SpeechOptions = {}): Promise<void> => call<void>('speech.start', options, 120_000);\n/** Yêu cầu dừng; tiếp tục nhận kết quả cuối và speech.end. */\nexport const stopSpeech = (): Promise<void> => call<void>('speech.stop');\n/** Nhận kết quả tạm thời/cuối cùng, lỗi và kết thúc phiên. Trả hàm huỷ đăng ký. */\nexport const onSpeech = <E extends keyof SpeechEvents>(event: E, listener: (data: SpeechEvents[E]) => void): (() => void) =>\n on(event, data => listener(data as SpeechEvents[E]));\n","import { getState } from './bridge';\nimport { notifyReady } from './apis/app';\n\nexport { getRouteParams, onContextChange } from './apis/route';\nexport { getAccessToken, getToken, type TokenType } from './apis/user';\nexport { closeApp, onAppPaused, onAppResumed } from './apis/app';\nexport {\n haptic,\n HapticType,\n openLink,\n openScreen,\n printImage,\n requestPayment,\n type OpenScreenRequest,\n type PaymentRequest,\n type PaymentResult,\n type PrintImageRequest,\n} from './apis/native';\nexport { isInHost } from './bridge';\nexport { MiniAppError, ErrorCode } from './errors';\nexport { SDK_VERSION } from './version';\nexport type { RouteParams } from './types';\n\n// Khởi tạo bridge ngay khi import (host có thể đẩy context trước khi app gọi hàm nào),\n// rồi báo \"ready\" khi DOM sẵn sàng.\nif (typeof window !== 'undefined') {\n getState();\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', notifyReady, { once: true });\n } else {\n queueMicrotask(notifyReady);\n }\n}\n\nexport { getBiometricAvailability, authenticateBiometric, type BiometryType, type BiometricAvailability, type BiometricRequest, type BiometricResult } from './apis/biometrics';\n\nexport { startSpeech, stopSpeech, onSpeech, type SpeechOptions, type SpeechResult, type SpeechError, type SpeechEvents } from './apis/speech';\n"]}
|