@retion-miniapp/react-native 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -182,9 +182,9 @@ interface MiniAppKeepAlive {
182
182
  /** Mini app đã đóng quá N ms → huỷ WebView (dừng timer / animation ngầm của web, tiết kiệm pin). */
183
183
  idle_close_ms?: number;
184
184
  }
185
+ /** Retion Mini App Platform (Vercel sin1 + Neon). Console: {MINIAPP_PLATFORM_URL}/console */
186
+ declare const MINIAPP_PLATFORM_URL = "https://retion-miniapp-platform.vercel.app";
185
187
  interface MiniAppConfig {
186
- /** Retion Mini App Platform, vd https://retion-miniapp-platform.vercel.app */
187
- platform_url: string;
188
188
  /** App ID của ứng dụng (Console → Ứng dụng). */
189
189
  host_id: string;
190
190
  /** Client Token của ứng dụng (Console → Ứng dụng → Thông tin tích hợp). */
@@ -267,6 +267,12 @@ interface MiniAppHostProps {
267
267
  * false: không bắt nút Back — dùng khi mini app là nội dung chính của màn / tab (đóng sẽ thành màn trống).
268
268
  */
269
269
  close_on_back?: boolean;
270
+ /**
271
+ * Tô nền đặc (trắng / #09090B theo is_dark) dưới mỗi WebView. Mặc định true: web không tự tô nền
272
+ * vẫn không lộ mini app khác đang chạy ngầm phía sau. false: nền trong suốt — container tự lo nền
273
+ * (vd. container có nền / hiệu ứng riêng muốn nhìn xuyên qua vùng web trống).
274
+ */
275
+ opaque_background?: boolean;
270
276
  /** WebView đã tải xong tài liệu local. Hữu ích để app cha ẩn launch splash sau khi mini app sẵn sàng hiện. */
271
277
  onWebLoadEnd?: (event: {
272
278
  app_id: string;
@@ -274,7 +280,7 @@ interface MiniAppHostProps {
274
280
  url: string;
275
281
  }) => void;
276
282
  }
277
- declare const _default: React.MemoExoticComponent<({ container, splash, is_dark, bridge, close_on_back, onWebLoadEnd }: MiniAppHostProps) => React.JSX.Element | null>;
283
+ declare const _default: React.MemoExoticComponent<({ container, splash, is_dark, bridge, close_on_back, opaque_background, onWebLoadEnd }: MiniAppHostProps) => React.JSX.Element | null>;
278
284
 
279
285
  interface OpenMiniAppArgs {
280
286
  app: MiniAppLaunch;
@@ -312,14 +318,59 @@ declare const closeMiniApp: () => void;
312
318
  *
313
319
  * Catalog (list manifest lần sync gần nhất) lưu storage → mở app offline vẫn biết app nào có bundle.
314
320
  */
315
- type MiniAppDownloadStatus = 'queued' | 'downloading' | 'installed' | 'failed';
321
+ /**
322
+ * Giống icon app trên iOS:
323
+ * - queued: chờ tới lượt (icon mờ) · downloading: tải lần đầu · updating: đã có bản cũ, đang tải bản mới
324
+ * - installed: mở được · failed: lỗi sau khi thử lại (has_local → vẫn mở bản cũ)
325
+ * - paused: app này bị pauseMiniApp(app_id) — nằm trong hàng đợi nhưng không tải tới khi resumeMiniApp
326
+ * - uninstalling: app không còn trong list, đang xoá
327
+ */
328
+ type MiniAppDownloadStatus = 'queued' | 'downloading' | 'updating' | 'installed' | 'failed' | 'paused' | 'uninstalling';
316
329
  interface MiniAppDownloadState {
317
330
  status: MiniAppDownloadStatus;
318
331
  /** 0–1 khi đang tải. */
319
332
  progress: number;
320
333
  version: string;
334
+ /** Máy đang có 1 bản (có thể cũ) → bấm mở được ngay. */
335
+ has_local: boolean;
321
336
  error?: string;
322
337
  }
338
+ type MiniAppEvent =
339
+ /** Status 1 app đổi (queued → downloading → installed …). */
340
+ {
341
+ type: 'status_change';
342
+ app_id: string;
343
+ state: MiniAppDownloadState;
344
+ }
345
+ /** % tải đổi (~250ms / lần). */
346
+ | {
347
+ type: 'progress';
348
+ app_id: string;
349
+ progress: number;
350
+ version: string;
351
+ }
352
+ /** App đã bị gỡ khỏi máy → Sảnh bỏ icon. */
353
+ | {
354
+ type: 'uninstalled';
355
+ app_id: string;
356
+ }
357
+ /** Sync list xong: app_ids = list hiện tại, removed = app bị gỡ. Hàng đợi vẫn đang tải tiếp. */
358
+ | {
359
+ type: 'sync_complete';
360
+ app_ids: string[];
361
+ removed: string[];
362
+ }
363
+ /** Sync lỗi (mạng / API / token) — catalog cũ giữ nguyên, app trong máy vẫn mở được. */
364
+ | {
365
+ type: 'sync_failed';
366
+ error: string;
367
+ }
368
+ /** Hàng đợi chuyển dừng ↔ chạy (pauseMiniAppDownloads / resumeMiniAppDownloads). reasons = lý do còn lại. */
369
+ | {
370
+ type: 'pause_change';
371
+ paused: boolean;
372
+ reasons: string[];
373
+ };
323
374
  /** Manifest từ API list ứng dụng (bundle_url tuyệt đối). */
324
375
  type MiniAppCatalogEntry = MiniAppManifest & {
325
376
  name?: string;
@@ -329,15 +380,57 @@ type MiniAppCatalogEntry = MiniAppManifest & {
329
380
  declare const useMiniAppDownload: (app_id: string | undefined) => MiniAppDownloadState | undefined;
330
381
  /** Hàng đợi đang dừng (còn lý do pause). */
331
382
  declare const useMiniAppDownloadsPaused: () => boolean;
383
+ /** Nghe thay đổi status / % tải của mọi mini app (vd cập nhật icon ở Sảnh). Trả hàm huỷ. */
384
+ declare const onMiniAppEvent: (listener: (event: MiniAppEvent) => void) => () => void;
385
+ /** Status hiện tại của mọi mini app — đọc 1 lần khi vẽ Sảnh, sau đó nghe onMiniAppEvent. */
386
+ declare const getMiniAppStatuses: () => Record<string, MiniAppDownloadState>;
387
+ type MiniAppSyncResult = {
388
+ ok: true;
389
+ app_ids: string[];
390
+ removed: string[];
391
+ } | {
392
+ ok: false;
393
+ error: string;
394
+ };
332
395
  /**
333
396
  * Lấy list mini app (theo config.channels — kênh đứng trước được ưu tiên) → cập nhật catalog
334
- * → cho app khác version vào hàng đợi. Lỗi mạng → giữ catalog cũ, không xoá gì.
397
+ * → cho app khác version vào hàng đợi. Lỗi mạng → giữ catalog cũ, không xoá gì, bắn sync_failed.
398
+ * Không bao giờ reject — kết quả trả về giống event sync_complete / sync_failed.
399
+ */
400
+ declare const syncMiniAppCatalog: () => Promise<MiniAppSyncResult>;
401
+ /**
402
+ * Người dùng gỡ mini app: bỏ khỏi hàng đợi, huỷ lượt tải đang chạy, xoá bundle, huỷ WebView (trừ khi
403
+ * đang mở). Ghi nhớ (storage) → sync không tải lại; tải lại bằng restoreMiniApp / người dùng bấm mở.
404
+ */
405
+ declare const uninstallMiniApp: (app_id: string) => Promise<void>;
406
+ /**
407
+ * Tải lại app người dùng đã gỡ (vd màn "Thêm app"): bỏ ghi nhớ đã gỡ → vào hàng đợi (`queued`).
408
+ * false: app không có trong list (chưa sync / admin đã tắt).
409
+ */
410
+ declare const restoreMiniApp: (app_id: string) => boolean;
411
+ /**
412
+ * Pause riêng 1 app: đang tải → huỷ (tải lại từ đầu khi resume), đang chờ → `paused`, chưa cần tải →
413
+ * nhớ lại, bản mới ở lần sync sau cũng `paused`. App khác vẫn tải bình thường. Người dùng bấm mở → tải luôn.
414
+ * Lưu storage: thoát app mở lại vẫn pause, chỉ tải khi resumeMiniApp / người dùng bấm mở / gỡ app.
335
415
  */
336
- declare const syncMiniAppCatalog: () => Promise<void>;
416
+ declare const pauseMiniApp: (app_id: string) => void;
417
+ /** Gỡ pause riêng của app → đang chờ thì về `queued` và hàng đợi chạy tiếp. */
418
+ declare const resumeMiniApp: (app_id: string) => void;
337
419
  /** Dừng hàng đợi vì `reason`. File đang tải (không phải do người dùng mở) bị huỷ, tải lại sau. */
338
420
  declare const pauseMiniAppDownloads: (reason: string) => void;
339
421
  /** Gỡ lý do dừng; hết lý do → chạy tiếp. */
340
422
  declare const resumeMiniAppDownloads: (reason: string) => void;
423
+ type MiniAppCatalogItem = MiniAppCatalogEntry & {
424
+ /** Máy đang có 1 bản (có thể cũ). */
425
+ installed: boolean;
426
+ /** Người dùng đã tự gỡ — sync không tải lại, chỉ tải khi restoreMiniApp. */
427
+ removed_by_user: boolean;
428
+ };
429
+ /**
430
+ * Mọi app trong list ứng dụng (lần sync gần nhất) kèm trạng thái — đọc đồng bộ, không gọi mạng.
431
+ * Dùng cho màn "Thêm app": lọc `!installed || removed_by_user`, tìm theo `name`, chọn → restoreMiniApp.
432
+ */
433
+ declare const getMiniAppCatalog: () => MiniAppCatalogItem[];
341
434
  /** app_id có trong catalog ứng dụng (đã phát hành) — đọc sync, không gọi mạng. */
342
435
  declare const getMiniAppCatalogEntry: (app_id: string) => MiniAppCatalogEntry | undefined;
343
436
  /**
@@ -361,4 +454,4 @@ declare class BridgeError extends Error {
361
454
  constructor(code: string, message: string);
362
455
  }
363
456
 
364
- export { DefaultMiniAppSplash, type MiniAppBridgeOptions, type MiniAppCatalogEntry, type MiniAppChannel, type MiniAppConfig, type MiniAppContainerProps, type MiniAppContext, type MiniAppDownloadState, type MiniAppDownloadStatus, type MiniAppDownloadTask, type MiniAppFileSystem, type MiniAppHandlerContext, _default as MiniAppHost, type MiniAppHostData, BridgeError as MiniAppHostError, type MiniAppHostProps, type MiniAppKeepAlive, type MiniAppLaunch, type MiniAppLocalBundle, type MiniAppManifest, type MiniAppNativeHandlers, type MiniAppPaymentRequest, type MiniAppPaymentResult, type MiniAppPermission, type MiniAppSplashProps, type MiniAppStorage, type OpenMiniAppArgs, closeMiniApp, configureMiniApp, createMmkvStorage, createRnfsFileSystem, ensureMiniApp, getLocalMiniApp, getMiniAppCatalogEntry, openMiniApp, pauseMiniAppDownloads, preloadMiniApp, resumeMiniAppDownloads, sendEventToWeb, syncMiniAppCatalog, useMiniAppDownload, useMiniAppDownloadsPaused };
457
+ export { DefaultMiniAppSplash, MINIAPP_PLATFORM_URL, type MiniAppBridgeOptions, type MiniAppCatalogEntry, type MiniAppCatalogItem, type MiniAppChannel, type MiniAppConfig, type MiniAppContainerProps, type MiniAppContext, type MiniAppDownloadState, type MiniAppDownloadStatus, type MiniAppDownloadTask, type MiniAppEvent, type MiniAppFileSystem, type MiniAppHandlerContext, _default as MiniAppHost, type MiniAppHostData, BridgeError as MiniAppHostError, type MiniAppHostProps, type MiniAppKeepAlive, type MiniAppLaunch, type MiniAppLocalBundle, type MiniAppManifest, type MiniAppNativeHandlers, type MiniAppPaymentRequest, type MiniAppPaymentResult, type MiniAppPermission, type MiniAppSplashProps, type MiniAppStorage, type MiniAppSyncResult, type OpenMiniAppArgs, closeMiniApp, configureMiniApp, createMmkvStorage, createRnfsFileSystem, ensureMiniApp, getLocalMiniApp, getMiniAppCatalog, getMiniAppCatalogEntry, getMiniAppStatuses, onMiniAppEvent, openMiniApp, pauseMiniApp, pauseMiniAppDownloads, preloadMiniApp, restoreMiniApp, resumeMiniApp, resumeMiniAppDownloads, sendEventToWeb, syncMiniAppCatalog, uninstallMiniApp, useMiniAppDownload, useMiniAppDownloadsPaused };
package/dist/index.d.ts CHANGED
@@ -182,9 +182,9 @@ interface MiniAppKeepAlive {
182
182
  /** Mini app đã đóng quá N ms → huỷ WebView (dừng timer / animation ngầm của web, tiết kiệm pin). */
183
183
  idle_close_ms?: number;
184
184
  }
185
+ /** Retion Mini App Platform (Vercel sin1 + Neon). Console: {MINIAPP_PLATFORM_URL}/console */
186
+ declare const MINIAPP_PLATFORM_URL = "https://retion-miniapp-platform.vercel.app";
185
187
  interface MiniAppConfig {
186
- /** Retion Mini App Platform, vd https://retion-miniapp-platform.vercel.app */
187
- platform_url: string;
188
188
  /** App ID của ứng dụng (Console → Ứng dụng). */
189
189
  host_id: string;
190
190
  /** Client Token của ứng dụng (Console → Ứng dụng → Thông tin tích hợp). */
@@ -267,6 +267,12 @@ interface MiniAppHostProps {
267
267
  * false: không bắt nút Back — dùng khi mini app là nội dung chính của màn / tab (đóng sẽ thành màn trống).
268
268
  */
269
269
  close_on_back?: boolean;
270
+ /**
271
+ * Tô nền đặc (trắng / #09090B theo is_dark) dưới mỗi WebView. Mặc định true: web không tự tô nền
272
+ * vẫn không lộ mini app khác đang chạy ngầm phía sau. false: nền trong suốt — container tự lo nền
273
+ * (vd. container có nền / hiệu ứng riêng muốn nhìn xuyên qua vùng web trống).
274
+ */
275
+ opaque_background?: boolean;
270
276
  /** WebView đã tải xong tài liệu local. Hữu ích để app cha ẩn launch splash sau khi mini app sẵn sàng hiện. */
271
277
  onWebLoadEnd?: (event: {
272
278
  app_id: string;
@@ -274,7 +280,7 @@ interface MiniAppHostProps {
274
280
  url: string;
275
281
  }) => void;
276
282
  }
277
- declare const _default: React.MemoExoticComponent<({ container, splash, is_dark, bridge, close_on_back, onWebLoadEnd }: MiniAppHostProps) => React.JSX.Element | null>;
283
+ declare const _default: React.MemoExoticComponent<({ container, splash, is_dark, bridge, close_on_back, opaque_background, onWebLoadEnd }: MiniAppHostProps) => React.JSX.Element | null>;
278
284
 
279
285
  interface OpenMiniAppArgs {
280
286
  app: MiniAppLaunch;
@@ -312,14 +318,59 @@ declare const closeMiniApp: () => void;
312
318
  *
313
319
  * Catalog (list manifest lần sync gần nhất) lưu storage → mở app offline vẫn biết app nào có bundle.
314
320
  */
315
- type MiniAppDownloadStatus = 'queued' | 'downloading' | 'installed' | 'failed';
321
+ /**
322
+ * Giống icon app trên iOS:
323
+ * - queued: chờ tới lượt (icon mờ) · downloading: tải lần đầu · updating: đã có bản cũ, đang tải bản mới
324
+ * - installed: mở được · failed: lỗi sau khi thử lại (has_local → vẫn mở bản cũ)
325
+ * - paused: app này bị pauseMiniApp(app_id) — nằm trong hàng đợi nhưng không tải tới khi resumeMiniApp
326
+ * - uninstalling: app không còn trong list, đang xoá
327
+ */
328
+ type MiniAppDownloadStatus = 'queued' | 'downloading' | 'updating' | 'installed' | 'failed' | 'paused' | 'uninstalling';
316
329
  interface MiniAppDownloadState {
317
330
  status: MiniAppDownloadStatus;
318
331
  /** 0–1 khi đang tải. */
319
332
  progress: number;
320
333
  version: string;
334
+ /** Máy đang có 1 bản (có thể cũ) → bấm mở được ngay. */
335
+ has_local: boolean;
321
336
  error?: string;
322
337
  }
338
+ type MiniAppEvent =
339
+ /** Status 1 app đổi (queued → downloading → installed …). */
340
+ {
341
+ type: 'status_change';
342
+ app_id: string;
343
+ state: MiniAppDownloadState;
344
+ }
345
+ /** % tải đổi (~250ms / lần). */
346
+ | {
347
+ type: 'progress';
348
+ app_id: string;
349
+ progress: number;
350
+ version: string;
351
+ }
352
+ /** App đã bị gỡ khỏi máy → Sảnh bỏ icon. */
353
+ | {
354
+ type: 'uninstalled';
355
+ app_id: string;
356
+ }
357
+ /** Sync list xong: app_ids = list hiện tại, removed = app bị gỡ. Hàng đợi vẫn đang tải tiếp. */
358
+ | {
359
+ type: 'sync_complete';
360
+ app_ids: string[];
361
+ removed: string[];
362
+ }
363
+ /** Sync lỗi (mạng / API / token) — catalog cũ giữ nguyên, app trong máy vẫn mở được. */
364
+ | {
365
+ type: 'sync_failed';
366
+ error: string;
367
+ }
368
+ /** Hàng đợi chuyển dừng ↔ chạy (pauseMiniAppDownloads / resumeMiniAppDownloads). reasons = lý do còn lại. */
369
+ | {
370
+ type: 'pause_change';
371
+ paused: boolean;
372
+ reasons: string[];
373
+ };
323
374
  /** Manifest từ API list ứng dụng (bundle_url tuyệt đối). */
324
375
  type MiniAppCatalogEntry = MiniAppManifest & {
325
376
  name?: string;
@@ -329,15 +380,57 @@ type MiniAppCatalogEntry = MiniAppManifest & {
329
380
  declare const useMiniAppDownload: (app_id: string | undefined) => MiniAppDownloadState | undefined;
330
381
  /** Hàng đợi đang dừng (còn lý do pause). */
331
382
  declare const useMiniAppDownloadsPaused: () => boolean;
383
+ /** Nghe thay đổi status / % tải của mọi mini app (vd cập nhật icon ở Sảnh). Trả hàm huỷ. */
384
+ declare const onMiniAppEvent: (listener: (event: MiniAppEvent) => void) => () => void;
385
+ /** Status hiện tại của mọi mini app — đọc 1 lần khi vẽ Sảnh, sau đó nghe onMiniAppEvent. */
386
+ declare const getMiniAppStatuses: () => Record<string, MiniAppDownloadState>;
387
+ type MiniAppSyncResult = {
388
+ ok: true;
389
+ app_ids: string[];
390
+ removed: string[];
391
+ } | {
392
+ ok: false;
393
+ error: string;
394
+ };
332
395
  /**
333
396
  * Lấy list mini app (theo config.channels — kênh đứng trước được ưu tiên) → cập nhật catalog
334
- * → cho app khác version vào hàng đợi. Lỗi mạng → giữ catalog cũ, không xoá gì.
397
+ * → cho app khác version vào hàng đợi. Lỗi mạng → giữ catalog cũ, không xoá gì, bắn sync_failed.
398
+ * Không bao giờ reject — kết quả trả về giống event sync_complete / sync_failed.
399
+ */
400
+ declare const syncMiniAppCatalog: () => Promise<MiniAppSyncResult>;
401
+ /**
402
+ * Người dùng gỡ mini app: bỏ khỏi hàng đợi, huỷ lượt tải đang chạy, xoá bundle, huỷ WebView (trừ khi
403
+ * đang mở). Ghi nhớ (storage) → sync không tải lại; tải lại bằng restoreMiniApp / người dùng bấm mở.
404
+ */
405
+ declare const uninstallMiniApp: (app_id: string) => Promise<void>;
406
+ /**
407
+ * Tải lại app người dùng đã gỡ (vd màn "Thêm app"): bỏ ghi nhớ đã gỡ → vào hàng đợi (`queued`).
408
+ * false: app không có trong list (chưa sync / admin đã tắt).
409
+ */
410
+ declare const restoreMiniApp: (app_id: string) => boolean;
411
+ /**
412
+ * Pause riêng 1 app: đang tải → huỷ (tải lại từ đầu khi resume), đang chờ → `paused`, chưa cần tải →
413
+ * nhớ lại, bản mới ở lần sync sau cũng `paused`. App khác vẫn tải bình thường. Người dùng bấm mở → tải luôn.
414
+ * Lưu storage: thoát app mở lại vẫn pause, chỉ tải khi resumeMiniApp / người dùng bấm mở / gỡ app.
335
415
  */
336
- declare const syncMiniAppCatalog: () => Promise<void>;
416
+ declare const pauseMiniApp: (app_id: string) => void;
417
+ /** Gỡ pause riêng của app → đang chờ thì về `queued` và hàng đợi chạy tiếp. */
418
+ declare const resumeMiniApp: (app_id: string) => void;
337
419
  /** Dừng hàng đợi vì `reason`. File đang tải (không phải do người dùng mở) bị huỷ, tải lại sau. */
338
420
  declare const pauseMiniAppDownloads: (reason: string) => void;
339
421
  /** Gỡ lý do dừng; hết lý do → chạy tiếp. */
340
422
  declare const resumeMiniAppDownloads: (reason: string) => void;
423
+ type MiniAppCatalogItem = MiniAppCatalogEntry & {
424
+ /** Máy đang có 1 bản (có thể cũ). */
425
+ installed: boolean;
426
+ /** Người dùng đã tự gỡ — sync không tải lại, chỉ tải khi restoreMiniApp. */
427
+ removed_by_user: boolean;
428
+ };
429
+ /**
430
+ * Mọi app trong list ứng dụng (lần sync gần nhất) kèm trạng thái — đọc đồng bộ, không gọi mạng.
431
+ * Dùng cho màn "Thêm app": lọc `!installed || removed_by_user`, tìm theo `name`, chọn → restoreMiniApp.
432
+ */
433
+ declare const getMiniAppCatalog: () => MiniAppCatalogItem[];
341
434
  /** app_id có trong catalog ứng dụng (đã phát hành) — đọc sync, không gọi mạng. */
342
435
  declare const getMiniAppCatalogEntry: (app_id: string) => MiniAppCatalogEntry | undefined;
343
436
  /**
@@ -361,4 +454,4 @@ declare class BridgeError extends Error {
361
454
  constructor(code: string, message: string);
362
455
  }
363
456
 
364
- export { DefaultMiniAppSplash, type MiniAppBridgeOptions, type MiniAppCatalogEntry, type MiniAppChannel, type MiniAppConfig, type MiniAppContainerProps, type MiniAppContext, type MiniAppDownloadState, type MiniAppDownloadStatus, type MiniAppDownloadTask, type MiniAppFileSystem, type MiniAppHandlerContext, _default as MiniAppHost, type MiniAppHostData, BridgeError as MiniAppHostError, type MiniAppHostProps, type MiniAppKeepAlive, type MiniAppLaunch, type MiniAppLocalBundle, type MiniAppManifest, type MiniAppNativeHandlers, type MiniAppPaymentRequest, type MiniAppPaymentResult, type MiniAppPermission, type MiniAppSplashProps, type MiniAppStorage, type OpenMiniAppArgs, closeMiniApp, configureMiniApp, createMmkvStorage, createRnfsFileSystem, ensureMiniApp, getLocalMiniApp, getMiniAppCatalogEntry, openMiniApp, pauseMiniAppDownloads, preloadMiniApp, resumeMiniAppDownloads, sendEventToWeb, syncMiniAppCatalog, useMiniAppDownload, useMiniAppDownloadsPaused };
457
+ export { DefaultMiniAppSplash, MINIAPP_PLATFORM_URL, type MiniAppBridgeOptions, type MiniAppCatalogEntry, type MiniAppCatalogItem, type MiniAppChannel, type MiniAppConfig, type MiniAppContainerProps, type MiniAppContext, type MiniAppDownloadState, type MiniAppDownloadStatus, type MiniAppDownloadTask, type MiniAppEvent, type MiniAppFileSystem, type MiniAppHandlerContext, _default as MiniAppHost, type MiniAppHostData, BridgeError as MiniAppHostError, type MiniAppHostProps, type MiniAppKeepAlive, type MiniAppLaunch, type MiniAppLocalBundle, type MiniAppManifest, type MiniAppNativeHandlers, type MiniAppPaymentRequest, type MiniAppPaymentResult, type MiniAppPermission, type MiniAppSplashProps, type MiniAppStorage, type MiniAppSyncResult, type OpenMiniAppArgs, closeMiniApp, configureMiniApp, createMmkvStorage, createRnfsFileSystem, ensureMiniApp, getLocalMiniApp, getMiniAppCatalog, getMiniAppCatalogEntry, getMiniAppStatuses, onMiniAppEvent, openMiniApp, pauseMiniApp, pauseMiniAppDownloads, preloadMiniApp, restoreMiniApp, resumeMiniApp, resumeMiniAppDownloads, sendEventToWeb, syncMiniAppCatalog, uninstallMiniApp, useMiniAppDownload, useMiniAppDownloadsPaused };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var Et=Object.create;var oe=Object.defineProperty;var Tt=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Ct=Object.getPrototypeOf,Pt=Object.prototype.hasOwnProperty;var Ot=(e,t)=>{for(var n in t)oe(e,n,{get:t[n],enumerable:!0})},De=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Rt(t))!Pt.call(e,o)&&o!==n&&oe(e,o,{get:()=>t[o],enumerable:!(r=Tt(t,o))||r.enumerable});return e};var Ie=(e,t,n)=>(n=e!=null?Et(Ct(e)):{},De(t||!e||!e.__esModule?oe(n,"default",{value:e,enumerable:!0}):n,e)),kt=e=>De(oe({},"__esModule",{value:!0}),e);var Kt={};Ot(Kt,{DefaultMiniAppSplash:()=>Ee,MiniAppHost:()=>Mt,MiniAppHostError:()=>v,closeMiniApp:()=>z,configureMiniApp:()=>Le,createMmkvStorage:()=>Je,createRnfsFileSystem:()=>Be,ensureMiniApp:()=>he,getLocalMiniApp:()=>E,getMiniAppCatalogEntry:()=>be,openMiniApp:()=>pt,pauseMiniAppDownloads:()=>ft,preloadMiniApp:()=>ct,resumeMiniAppDownloads:()=>ht,sendEventToWeb:()=>st,syncMiniAppCatalog:()=>fe,useMiniAppDownload:()=>ge,useMiniAppDownloadsPaused:()=>dt});module.exports=kt(Kt);var q=null,$e=new Set,Le=e=>{q=e,$e.forEach(t=>t())},x=()=>{if(!q)throw new Error("[miniapp] Ch\u01B0a g\u1ECDi configureMiniApp()");return q},Ne=e=>{$e.add(e),q&&e()},B=(...e)=>{q!=null&&q.debug&&console.log("[miniapp]",...e)};var Be=(e,t)=>({document_dir:e.DocumentDirectoryPath,cache_dir:e.CachesDirectoryPath,exists:n=>e.exists(n),mkdir:n=>e.mkdir(n),remove:n=>e.unlink(n).catch(()=>{}),listDir:n=>e.readDir(n).then(r=>r.map(o=>o.name)).catch(()=>[]),sha256:n=>e.hash(n,"sha256"),unzip:async(n,r)=>{await t(n,r)},download:({url:n,to_file:r,onProgress:o})=>{let{jobId:a,promise:d}=e.downloadFile({fromUrl:n,toFile:r,progressInterval:250,begin:()=>{},progress:({bytesWritten:c,contentLength:i})=>o==null?void 0:o(c,i)});return{promise:d.then(({statusCode:c})=>({status:c})),cancel:()=>e.stopDownload(a)}}}),Je=e=>({getString:t=>e.getString(t),setString:(t,n)=>e.set(t,n)});var u=Ie(require("react")),w=require("react-native"),wt=Ie(require("react-native-webview"));var ie=require("react-native"),se=1,v=class extends Error{constructor(n,r){super(r);this.code=n}},Ve=e=>{try{let t=JSON.parse(e);return(t==null?void 0:t.__retion)===se&&typeof t.method=="string"?t:null}catch{return null}},ae=e=>`window.__RETION_MINIAPP__ && window.__RETION_MINIAPP__.receive(${JSON.stringify(e)}); true;`,We=(e,t)=>ae({id:e,result:t}),He=(e,t)=>ae({id:e,error:{code:t.code,message:t.message}}),ye=e=>ae({event:"context",data:e});var je=()=>`(function () {
1
+ "use strict";var qt=Object.create;var le=Object.defineProperty;var Ht=Object.getOwnPropertyDescriptor;var Ut=Object.getOwnPropertyNames;var Kt=Object.getPrototypeOf,zt=Object.prototype.hasOwnProperty;var Yt=(e,t)=>{for(var n in t)le(e,n,{get:t[n],enumerable:!0})},qe=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Ut(t))!zt.call(e,s)&&s!==n&&le(e,s,{get:()=>t[s],enumerable:!(r=Ht(t,s))||r.enumerable});return e};var He=(e,t,n)=>(n=e!=null?qt(Kt(e)):{},qe(t||!e||!e.__esModule?le(n,"default",{value:e,enumerable:!0}):n,e)),Qt=e=>qe(le({},"__esModule",{value:!0}),e);var fn={};Yt(fn,{DefaultMiniAppSplash:()=>Ne,MINIAPP_PLATFORM_URL:()=>ue,MiniAppHost:()=>$t,MiniAppHostError:()=>E,closeMiniApp:()=>ee,configureMiniApp:()=>Ke,createMmkvStorage:()=>Qe,createRnfsFileSystem:()=>Ye,ensureMiniApp:()=>xe,getLocalMiniApp:()=>T,getMiniAppCatalog:()=>kt,getMiniAppCatalogEntry:()=>ae,getMiniAppStatuses:()=>bt,onMiniAppEvent:()=>_t,openMiniApp:()=>Mt,pauseMiniApp:()=>Rt,pauseMiniAppDownloads:()=>Ct,preloadMiniApp:()=>wt,restoreMiniApp:()=>Tt,resumeMiniApp:()=>Pt,resumeMiniAppDownloads:()=>Ot,sendEventToWeb:()=>At,syncMiniAppCatalog:()=>be,uninstallMiniApp:()=>Et,useMiniAppDownload:()=>Se,useMiniAppDownloadsPaused:()=>St});module.exports=Qt(fn);var ue="https://retion-miniapp-platform.vercel.app",Q=null,Ue=new Set,Ke=e=>{Q=e,Ue.forEach(t=>t())},x=()=>{if(!Q)throw new Error("[miniapp] Ch\u01B0a g\u1ECDi configureMiniApp()");return Q},ze=e=>{Ue.add(e),Q&&e()},J=(...e)=>{Q!=null&&Q.debug&&console.log("[miniapp]",...e)};var Ye=(e,t)=>({document_dir:e.DocumentDirectoryPath,cache_dir:e.CachesDirectoryPath,exists:n=>e.exists(n),mkdir:n=>e.mkdir(n),remove:n=>e.unlink(n).catch(()=>{}),listDir:n=>e.readDir(n).then(r=>r.map(s=>s.name)).catch(()=>[]),sha256:n=>e.hash(n,"sha256"),unzip:async(n,r)=>{await t(n,r)},download:({url:n,to_file:r,onProgress:s})=>{let{jobId:o,promise:l}=e.downloadFile({fromUrl:n,toFile:r,progressInterval:250,begin:()=>{},progress:({bytesWritten:i,contentLength:p})=>s==null?void 0:s(i,p)});return{promise:l.then(({statusCode:i})=>({status:i})),cancel:()=>e.stopDownload(o)}}}),Qe=e=>({getString:t=>e.getString(t),setString:(t,n)=>e.set(t,n)});var u=He(require("react")),w=require("react-native"),Lt=He(require("react-native-webview"));var de=require("react-native"),ge=1,E=class extends Error{constructor(n,r){super(r);this.code=n}},Xe=e=>{try{let t=JSON.parse(e);return(t==null?void 0:t.__retion)===ge&&typeof t.method=="string"?t:null}catch{return null}},fe=e=>`window.__RETION_MINIAPP__ && window.__RETION_MINIAPP__.receive(${JSON.stringify(e)}); true;`,Ze=(e,t)=>fe({id:e,result:t}),et=(e,t)=>fe({id:e,error:{code:t.code,message:t.message}}),Ce=e=>fe({event:"context",data:e});var tt=()=>`(function () {
2
2
  var post = function (level, args) {
3
3
  try {
4
4
  var parts = [];
@@ -8,7 +8,7 @@
8
8
  else if (typeof a === 'object') { try { parts.push(JSON.stringify(a).slice(0, 800)); } catch (e) { parts.push(String(a)); } }
9
9
  else { parts.push(String(a)); }
10
10
  }
11
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${se}, method: 'log', level: level, text: parts.join(' ') }));
11
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${ge}, method: 'log', level: level, text: parts.join(' ') }));
12
12
  } catch (e) {}
13
13
  };
14
14
  ['log', 'info', 'warn', 'error'].forEach(function (level) {
@@ -19,7 +19,7 @@
19
19
  window.addEventListener('unhandledrejection', function (e) { post('error', ['[unhandledrejection]', e.reason]); });
20
20
  // Kh\xF4ng log query (c\xF3 th\u1EC3 ch\u1EE9a token) \u2014 ch\u1EC9 \u0111\u01B0\u1EDDng d\u1EABn + route.
21
21
  post('info', ['[page] ' + location.pathname + location.hash]);
22
- })(); true;`,qe=()=>`(function () {
22
+ })(); true;`,nt=()=>`(function () {
23
23
  function atTop(el) {
24
24
  for (var n = el; n && n !== document.documentElement; n = n.parentElement) {
25
25
  if (n.scrollTop > 0) { return false; }
@@ -30,7 +30,7 @@
30
30
  function report(at_top) {
31
31
  if (at_top === last) { return; }
32
32
  last = at_top;
33
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${se}, method: 'touchAtTop', at_top: at_top }));
33
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${ge}, method: 'touchAtTop', at_top: at_top }));
34
34
  }
35
35
  document.addEventListener('touchstart', function (e) { report(atTop(e.target)); }, { capture: true, passive: true });
36
36
  // Cu\u1ED9n r\u1EDDi \u0111\u1EA7u trang \u2192 b\xE1o ngay, kh\xF4ng \u0111\u1EE3i l\u1EA7n ch\u1EA1m sau (tr\xE1nh host d\xF9ng gi\xE1 tr\u1ECB c\u0169 "\u0111ang \u1EDF \u0111\u1EA7u").
@@ -38,8 +38,8 @@
38
38
  var el = e.target === document ? document.documentElement : e.target;
39
39
  if (el && el.scrollTop > 0) { report(false); }
40
40
  }, { capture: true, passive: true });
41
- })(); true;`,Ue=e=>ae({event:e}),Ke=(e,t)=>{let n=ze(t);return`try { history.replaceState(history.state, '', location.pathname + ${JSON.stringify(n?`?${n}`:"")} + location.hash); } catch (e) {}
42
- ${ye(e)}`},ze=e=>Object.entries(e).filter(([,t])=>t!=null&&t!=="").map(([t,n])=>`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`).join("&"),Qe=(e,t={})=>{let n=ze(t);return`window.__RETION_MINIAPP_HOST__ = { protocol: ${se} };
41
+ })(); true;`,rt=e=>fe({event:e}),ot=(e,t)=>{let n=st(t);return`try { history.replaceState(history.state, '', location.pathname + ${JSON.stringify(n?`?${n}`:"")} + location.hash); } catch (e) {}
42
+ ${Ce(e)}`},st=e=>Object.entries(e).filter(([,t])=>t!=null&&t!=="").map(([t,n])=>`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`).join("&"),it=(e,t={})=>{let n=st(t);return`window.__RETION_MINIAPP_HOST__ = { protocol: ${ge} };
43
43
  window.__RETION_MINIAPP_CONTEXT__ = ${JSON.stringify(e)};
44
44
  ${n?`try { history.replaceState(history.state, '', location.pathname + '?' + ${JSON.stringify(n)} + location.hash); } catch (e) {}`:""}
45
- true;`},Ye={partner:"partner_token",chatbox:"chatbox_token"},Ge=(e,t)=>{let n={...e};for(let r of Object.values(Ye))t.includes(r)||delete n[r];return n},we=new Set,Fe=async(e,t)=>{if(we.has(e))throw new v("BUSY",`${e} \u0111ang ch\u1EA1y \u2014 ch\u1EDD l\u01B0\u1EE3t tr\u01B0\u1EDBc xong`);we.add(e);try{return await t()}finally{we.delete(e)}},Me=(e,t)=>{if(typeof e!="string"||!e)throw new v("INVALID_PARAMS",`Thi\u1EBFu ${t}`);return e},Xe=async({method:e,params:t},{getHostData:n,getPermissions:r,is_dark:o,close:a,app_id:d,instance_id:c,options:i})=>{var b,A,T,p;let f=i==null?void 0:i.handlers,h={app_id:d,instance_id:c,close:a},g=()=>new v("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF \u1EE9ng d\u1EE5ng n\xE0y`);switch(e){case"requestPayment":{let l=f==null?void 0:f.requestPayment;if(!l)throw g();let _=t==null?void 0:t.amount;if(typeof _!="number"||!Number.isFinite(_)||_<=0)throw new v("INVALID_PARAMS","amount ph\u1EA3i l\xE0 s\u1ED1 > 0");let R={...t,amount:_,currency:Me(t==null?void 0:t.currency,"currency")};return Fe(e,()=>l(R,h))}case"printImage":{let l=f==null?void 0:f.printImage;if(!l)throw g();let _=Me(t==null?void 0:t.image,"image");await Fe(e,()=>l({image:_},h));return}case"openScreen":if(!(f!=null&&f.openScreen))throw g();await f.openScreen({screen:Me(t==null?void 0:t.screen,"screen"),params:t==null?void 0:t.params},h);return;case"closeApp":a();return;case"openWebview":{let l=String((b=t==null?void 0:t.url)!=null?b:"");if(!/^https?:\/\//i.test(l))throw new v("INVALID_PARAMS","url ph\u1EA3i l\xE0 http(s)");await(i!=null&&i.openUrl?i.openUrl(l):ie.Linking.openURL(l));return}case"showToast":(T=i==null?void 0:i.showToast)==null||T.call(i,String((A=t==null?void 0:t.message)!=null?A:""));return;case"getSystemInfo":return{platform:ie.Platform.OS==="ios"?"ios":"android",appVersion:(p=i==null?void 0:i.app_version)!=null?p:"",theme:o?"dark":"light"};case"getAccessToken":{let l=n().access_token;if(!l)throw new v("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return l}case"getToken":{let l=t==null?void 0:t.type;if(l==="access"){let W=n().access_token;if(!W)throw new v("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return W}if(l!=="partner"&&l!=="chatbox")throw new v("HOST_ERROR",`Lo\u1EA1i token kh\xF4ng h\u1EE3p l\u1EC7: ${String(l)}`);let _=Ye[l];if(!r().includes(_))throw new v("PERMISSION_DENIED",`Mini app ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5p quy\u1EC1n ${_} (Console \u2192 Quy\u1EC1n l\u1EA5y token)`);let R=l==="partner"?n().partner_token:n().chatbox_token;if(!R)throw new v("HOST_ERROR",`Kh\xF4ng c\xF3 ${_}`);return R}case"getUserInfo":{let l=n().user;if(!l)throw new v("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin nh\xE2n vi\xEAn");return l}case"getPageInfo":{let l=n().page;if(!l)throw new v("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin page");return l}case"sendMessage":case"insertText":throw new v("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF phi\xEAn b\u1EA3n app n\xE0y`);default:throw new v("NOT_SUPPORTED",`API kh\xF4ng t\u1ED3n t\u1EA1i: ${e}`)}};var tt=e=>`bundle:${e}`,nt=()=>`${x().file_system.document_dir}/miniapps`,rt=(e,t,n="index.html",r=!1,o=[])=>{let a=`${nt()}/${e}/${t}`;return{app_id:e,version:t,dir:a,entry_uri:`file://${a}/${n}`,context_update:r,permissions:o}},Ze=e=>{var t;x().storage.setString(tt(e.app_id),JSON.stringify({version:e.version,entry:e.entry,context_update:!!e.context_update,permissions:(t=e.permissions)!=null?t:[]}))},Dt=(e,t)=>/^https?:\/\//.test(t)?t:`${e.replace(/[^/]*$/,"")}${t}`,E=e=>{let t=x().storage.getString(tt(e));if(!t)return null;try{let{version:n,entry:r,context_update:o,permissions:a}=JSON.parse(t);return rt(e,n,r,!!o,Array.isArray(a)?a:[])}catch{return null}},ce=e=>x().file_system.exists(e.entry_uri.replace("file://","")),_e=async e=>{let t=E(e.app_id);return(t==null?void 0:t.version)===e.version&&await ce(t)},It=async(e,t)=>{let n=x().file_system,r=`${nt()}/${e}`,o=await n.listDir(r).catch(()=>[]);await Promise.all(o.filter(a=>!t.includes(a)).map(a=>n.remove(`${r}/${a}`).catch(()=>{})))},K=class extends Error{constructor(){super("cancelled"),this.name="MiniAppInstallCancelled"}},pe={},ve=(e,{base_url:t,onProgress:n}={})=>{var b;let r=x().file_system,o=null,a=!1,d=`${r.cache_dir}/${e.app_id}-${e.version}.zip`,c=()=>{if(a)throw new K},i=async()=>{var p;c();let A=E(e.app_id);if((A==null?void 0:A.version)===e.version&&await r.exists(A.dir))return Ze(e),E(e.app_id);c();let T=r.download({url:t?Dt(t,e.bundle_url):e.bundle_url,to_file:d,onProgress:(l,_)=>{var W;let R=_>0?_:(W=e.size)!=null?W:0;R>0&&(n==null||n(Math.min(1,l/R)))}});o=T;try{let{status:l}=await T.promise;if(c(),l!==200)throw new Error(`bundle ${l}`);if(e.sha256)if(r.sha256){if(await r.sha256(d)!==e.sha256)throw new Error("sha256 mismatch")}else B("b\u1ECF qua ki\u1EC3m tra sha256 (file_system kh\xF4ng c\xF3 sha256)",e.app_id);c();let _=rt(e.app_id,e.version,e.entry,!!e.context_update,(p=e.permissions)!=null?p:[]);return await r.remove(_.dir).catch(()=>{}),await r.mkdir(_.dir),await r.unzip(d,_.dir),Ze(e),It(e.app_id,[e.version,A==null?void 0:A.version].filter(Boolean)),_}catch(l){throw a?new K:l}finally{o=null,r.remove(d).catch(()=>{})}},h=((b=pe[e.app_id])!=null?b:Promise.resolve()).catch(()=>{}).then(i),g=h.catch(()=>{});return pe[e.app_id]=g,g.then(()=>{pe[e.app_id]===g&&delete pe[e.app_id]}),{promise:h,cancel:()=>{a=!0,o==null||o.cancel()}}},ee={},$t=__DEV__?0:60*1e3,et={},ot=(e,t)=>{var r,o;let n=E(e);return n&&Date.now()-((r=et[t])!=null?r:0)<$t?Promise.resolve(n):((o=ee[e])!=null||(ee[e]=(async()=>{let a=await fetch(t,{headers:{"Cache-Control":"no-cache"}});if(!a.ok)throw new Error(`manifest ${a.status}`);let d=await a.json(),c=await ve(d,{base_url:t}).promise;return et[t]=Date.now(),c})().catch(a=>(console.warn("[miniapp] sync failed",e,a==null?void 0:a.message),E(e))).finally(()=>{ee[e]=void 0})),ee[e])};var le=new Map,it=(e,t)=>(le.set(e,t),()=>{le.get(e)===t&&le.delete(e)}),st=(e,t)=>{let n=le.get(e);return n?n(t):!1};var ue=require("react"),de=e=>{let t=e,n=new Set;return{getState:()=>t,setState:r=>{let o=typeof r=="function"?r(t):r;t={...t,...o},n.forEach(a=>a())},subscribe:r=>(n.add(r),()=>{n.delete(r)})}},J=(e,t,n=Object.is)=>{let r=(0,ue.useRef)(null),o=()=>{let a=e.getState(),d=r.current;if(d&&d.state===a&&d.selector===t)return d.value;let c=t(a),i=d&&n(d.value,c)?d.value:c;return r.current={state:a,selector:t,value:i},i};return(0,ue.useSyncExternalStore)(e.subscribe,o)};var $=de({active_key:null,instances:{}}),at=({app:e,instance_id:t,context:n={},url_params:r={},host_data:o={}},a)=>{var c;let d=(c=x().keep_alive)==null?void 0:c.max_webviews;$.setState(i=>{let f=t!=null?t:e.app_id,h={...i.instances,[f]:{key:f,app:e,context:n,url_params:r,host_data:o,last_used_at:Date.now()}},g=Object.keys(h);return d&&d>0&&g.length>d&&g.filter(b=>b!==f).sort((b,A)=>h[b].last_used_at-h[A].last_used_at).slice(0,g.length-d).forEach(b=>{delete h[b]}),a?{active_key:f,instances:h}:{instances:h}})},pt=e=>at(e,!0),ct=e=>at(e,!1),z=()=>$.setState({active_key:null}),lt=e=>{$.setState(t=>{if(t.active_key===e||!t.instances[e])return{};let n={...t.instances};return delete n[e],{instances:n}})};var ut="catalog",Lt=10*1e3,Nt=2,Bt=3e3,Jt=()=>{var e;try{return JSON.parse((e=x().storage.getString(ut))!=null?e:"{}")}catch{return{}}},C=de({catalog:{},downloads:{},pause_reasons:[]});Ne(()=>C.setState({catalog:Jt()}));var ge=e=>J(C,t=>e?t.downloads[e]:void 0),dt=()=>J(C,e=>e.pause_reasons.length>0),Y=(...e)=>B("queue",...e),L=[],Q={},S=null,U={},V=(e,t)=>{C.setState(n=>{let r=n.downloads[e];return{downloads:{...n.downloads,[e]:{...r!=null?r:{status:"queued",progress:0},...t}}}})},Se=(e,t)=>{var n;(n=U[e])==null||n.forEach(r=>r(t)),delete U[e]},Ft=()=>C.getState().pause_reasons.length>0,G=e=>{var c;if(S)return;let t=e?L.indexOf(e):Ft()?-1:0;if(t<0||t>=L.length)return;let[n]=L.splice(t,1),r=C.getState().catalog[n];if(!r){Se(n,E(n)),G();return}let o=Date.now();Q[n]=((c=Q[n])!=null?c:0)+1,V(n,{status:"downloading",progress:0,version:r.version,error:void 0});let a=0,d=ve(r,{onProgress:i=>{let f=Math.floor(i*100);f!==a&&(a=f,V(n,{progress:f/100,version:r.version}))}});S={app_id:n,handle:d,forced:!!e},Y("start",n,r.version,e?"(forced)":""),d.promise.then(i=>{Y("installed",n,r.version,`${Date.now()-o}ms`),V(n,{status:"installed",progress:1,version:r.version}),Se(n,i)}).catch(i=>{var h;if(i instanceof K){Y("paused",n),Q[n]-=1,L.unshift(n),V(n,{status:"queued",progress:0,version:r.version});return}let f=String((h=i==null?void 0:i.message)!=null?h:i);if(console.warn("[miniapp-queue] failed",n,f),Q[n]<Nt){V(n,{status:"queued",progress:0,version:r.version,error:f}),setTimeout(()=>{var g;L.includes(n)||(S==null?void 0:S.app_id)===n||(L.push(n),G((g=U[n])!=null&&g.length?n:void 0))},Bt);return}V(n,{status:"failed",progress:0,version:r.version,error:f}),Se(n,E(n))}).finally(()=>{S=null;let i=L.find(f=>{var h;return(h=U[f])==null?void 0:h.length});G(i)})},gt=(e,{front:t=!1}={})=>{if((S==null?void 0:S.app_id)===e)return;let n=L.indexOf(e);if(n>=0){if(!t)return;L.splice(n,1)}t?L.unshift(e):L.push(e)},Vt=async e=>{let{platform_url:t,host_id:n,client_token:r}=x(),o=new AbortController,a=setTimeout(()=>o.abort(),Lt);try{let d=`${t}/api/hosts/${encodeURIComponent(n)}/miniapps?channel=${e}`,c=await fetch(d,{headers:{Authorization:`Bearer ${r}`,"Cache-Control":"no-cache"},signal:o.signal});if(!c.ok)throw new Error(`host list ${e} ${c.status}`);return(await c.json()).apps.map(f=>({...f,channel:e}))}finally{clearTimeout(a)}},te=null,fe=()=>(te!=null||(te=(async()=>{let e=Date.now();try{let t=await Promise.all(x().channels.map(Vt)),n={};[...t].reverse().flat().forEach(o=>{n[o.app_id]=o}),x().storage.setString(ut,JSON.stringify(n)),C.setState({catalog:n});let r=[];for(let o of Object.values(n))await _e(o)?V(o.app_id,{status:"installed",progress:1,version:o.version}):r.push(o);r.forEach(o=>{Q[o.app_id]=0,V(o.app_id,{status:"queued",progress:0,version:o.version,error:void 0}),gt(o.app_id)}),Y("catalog",Object.keys(n).length,"apps, outdated",r.map(o=>o.app_id),`${Date.now()-e}ms`),G()}catch(t){console.warn("[miniapp-queue] sync catalog failed",t==null?void 0:t.message)}finally{te=null}})()),te),ft=e=>{let{pause_reasons:t}=C.getState();t.includes(e)||(C.setState({pause_reasons:[...t,e]}),Y("pause",e),S&&!S.forced&&S.handle.cancel())},ht=e=>{let{pause_reasons:t}=C.getState();t.includes(e)&&(C.setState({pause_reasons:t.filter(n=>n!==e)}),Y("resume",e),G())},be=e=>C.getState().catalog[e],he=async e=>{let t=be(e);if(!t)return;if(await _e(t))return E(e);let n=new Promise(r=>{var o;((o=U[e])!=null?o:U[e]=[]).push(r)});return(S==null?void 0:S.app_id)===e?S.forced=!0:(Q[e]=0,gt(e,{front:!0}),S&&!S.forced?S.handle.cancel():G(e)),n};var M=require("react/jsx-runtime"),xe=e=>(e!=null?e:"").replace(/\?[^#]*/,""),mt=0,Wt=()=>{let e=new Set;return{emit:t=>e.forEach(n=>n(t)),subscribe:t=>(e.add(t),()=>{e.delete(t)})}},Ht=u.default.memo(({instance_key:e,is_active:t,is_dark:n,reload_tick:r,web_at_top:o,splash:a,bridge:d,onWebLoadEnd:c})=>{var Oe,ke;let i=(0,u.useRef)(null),f=(0,u.useRef)(!1),h=J($,s=>s.instances[e]),g=h==null?void 0:h.app.app_id,b=h==null?void 0:h.app.manifest_url,A=h==null?void 0:h.context,T=h==null?void 0:h.url_params,[p,l]=(0,u.useState)(()=>g?E(g):null),[_,R]=(0,u.useState)(!1),[W,Te]=(0,u.useState)(0),[yt,X]=(0,u.useState)(0),[_t,D]=(0,u.useState)(!1),N=(0,u.useRef)(null),Re=s=>{N.current&&clearTimeout(N.current),N.current=setTimeout(()=>{N.current=null,D(!0)},s)};(0,u.useEffect)(()=>()=>{N.current&&clearTimeout(N.current)},[]),(0,u.useEffect)(()=>{if(!g||!t&&p)return;let s=!0;return R(!1),(async()=>{let m=E(g),P=m?await ce(m):!1;if(!s||(l(P?I=>!I||I.version!==m.version||I.permissions.join(",")!==m.permissions.join(",")?m:I:null),__DEV__&&Date.now()-mt>1e4&&(mt=Date.now(),await fe()),!s))return;let F=await he(g),H=F!==void 0?F:b?await ot(g,b):E(g);if(s){if(!H){R(!0);return}l(I=>I!=null?I:H)}})(),()=>{s=!1}},[t,g,b,W]),(0,u.useEffect)(()=>it(e,s=>i.current?(i.current.postMessage(s),!0):!1),[e]);let vt=J(C,s=>{let m=g?s.downloads[g]:void 0;return(m==null?void 0:m.status)==="installed"?m.version:void 0});(0,u.useEffect)(()=>{if(t||!g||!p)return;let s=E(g);if(!s||s.version===p.version)return;let m=!0;return ce(s).then(P=>{!m||!P||(B(`webview:${e}`,"\u0111\u1ED5i bundle (\u1EA9n)",p.version,"\u2192",s.version),l(s))}),()=>{m=!1}},[t,g,vt,p==null?void 0:p.version]),(0,u.useEffect)(()=>{var P;let s=(P=x().keep_alive)==null?void 0:P.idle_close_ms;if(t||!s||s<=0)return;let m=setTimeout(()=>{lt(e)},s);return()=>clearTimeout(m)},[t,e]),(0,u.useEffect)(()=>{r>0&&(R(!1),D(!1),X(s=>s+1),Te(s=>s+1))},[r]);let Ce=(0,u.useRef)(t);(0,u.useEffect)(()=>{var s;Ce.current!==t&&(Ce.current=t,f.current&&((s=i.current)==null||s.injectJavaScript(Ue(t?"resumed":"paused"))))},[t]);let ne=`${(Oe=p==null?void 0:p.version)!=null?Oe:"none"}:${(ke=p==null?void 0:p.permissions.join(","))!=null?ke:""}:${yt}`,Z=(0,u.useMemo)(()=>JSON.stringify([A!=null?A:{},T!=null?T:{}]),[A,T]),me=(0,u.useMemo)(()=>{var s;return Ge(T!=null?T:{},(s=p==null?void 0:p.permissions)!=null?s:[])},[Z,p==null?void 0:p.permissions]),St=(0,u.useMemo)(()=>Qe(A!=null?A:{},me)+qe()+(x().debug?je():""),[me]),re=(0,u.useRef)(null),Pe=(0,u.useRef)(null);(0,u.useEffect)(()=>{var m,P,F;if(!p)return;if(Pe.current!==ne){Pe.current=ne,re.current=Z;return}if(re.current===Z)return;let s=((P=JSON.parse((m=re.current)!=null?m:"[]")[0])!=null?P:{}).org_id;if(re.current=Z,s===(A==null?void 0:A.org_id)&&f.current){D(!1),Re(1500),(F=i.current)==null||F.injectJavaScript(Ke(A!=null?A:{},me));return}D(!1),X(H=>H+1)},[Z,p,ne]);let bt=(0,u.useCallback)(async s=>{var P,F,H,I,Ae;let m=Ve(s.nativeEvent.data);if(!m){if(g&&(d!=null&&d.onWebEvent))try{Promise.resolve(d.onWebEvent(s.nativeEvent.data,{app_id:g,instance_id:e})).catch(y=>{console.warn("[miniapp] onWebEvent l\u1ED7i",g,y)})}catch(y){console.warn("[miniapp] onWebEvent l\u1ED7i",g,y)}return}if(m.method==="log"){let{level:y,text:O}=m;B(`web:${e}`,y!=null?y:"log",O!=null?O:"");return}if(m.method==="pong"){N.current||D(!0);return}if(m.method==="touchAtTop"){o.emit(!!m.at_top);return}if(m.method==="contextApplied"){N.current&&clearTimeout(N.current),N.current=null,D(!0);return}if(m.method==="ready"){f.current=!0,D(!0);let y=(P=$.getState().instances[e])==null?void 0:P.context;y&&((F=i.current)==null||F.injectJavaScript(ye(y)));return}try{let y=await Xe(m,{getHostData:()=>{var O,j;return(j=(O=$.getState().instances[e])==null?void 0:O.host_data)!=null?j:{}},getPermissions:()=>{var O,j;return g?(j=(O=E(g))==null?void 0:O.permissions)!=null?j:[]:[]},is_dark:n,close:z,app_id:g!=null?g:"",instance_id:e,options:d});m.id&&((H=i.current)==null||H.injectJavaScript(We(m.id,y)))}catch(y){if(!m.id)return;let O=y==null?void 0:y.code,j=y instanceof v?y:new v(typeof O=="string"?O:"HOST_ERROR",String((I=y==null?void 0:y.message)!=null?I:y));(Ae=i.current)==null||Ae.injectJavaScript(He(m.id,j))}},[e,n,g,o,d]),xt=(0,u.useCallback)(()=>{R(!1),X(s=>s+1),Te(s=>s+1)},[]);return(0,M.jsxs)(w.View,{style:[w.StyleSheet.absoluteFill,!t&&k.behind],pointerEvents:t?"auto":"none",children:[p?(0,M.jsx)(wt.default,{ref:i,source:{uri:p.entry_uri},originWhitelist:["*"],allowingReadAccessToURL:`file://${p.dir}`,allowFileAccess:!0,allowFileAccessFromFileURLs:!0,allowUniversalAccessFromFileURLs:!0,injectedJavaScriptBeforeContentLoaded:St,onMessage:bt,bounces:!1,overScrollMode:"never",onLoadStart:s=>{B(`webview:${e}`,"load start",xe(s.nativeEvent.url)),f.current=!1,D(!1)},onError:s=>{B(`webview:${e}`,"load error",xe(s.nativeEvent.url),s.nativeEvent.description),R(!0),D(!1)},onLoadEnd:s=>{let m=s.nativeEvent.url;B(`webview:${e}`,"load end",xe(m)),g&&(c==null||c({app_id:g,instance_id:e,url:m})),Re(1500)},onContentProcessDidTerminate:()=>{f.current=!1,D(!1),X(s=>s+1)},onRenderProcessGone:()=>(f.current=!1,D(!1),X(s=>s+1),!0),style:k.webview},ne):null,h&&(0,M.jsx)(qt,{visible:!p||!_t,interactive:_,children:(0,M.jsx)(jt,{splash:a,app:h.app,is_dark:n,error:_,has_bundle:!!p,retry:xt})})]})}),jt=u.default.memo(({splash:e,app:t,is_dark:n,error:r,has_bundle:o,retry:a})=>{let d=e,c=ge(t.app_id),i=r?"error":!o&&(c==null?void 0:c.status)==="downloading"?"downloading":"loading";return(0,M.jsx)(d,{app:t,is_dark:n,status:i,progress:i==="downloading"?c==null?void 0:c.progress:void 0,retry:a})}),qt=({visible:e,interactive:t,children:n})=>{let r=(0,u.useRef)(new w.Animated.Value(e?1:0)).current,[o,a]=(0,u.useState)(e);return(0,u.useEffect)(()=>{if(e){a(!0),r.setValue(1);return}let d=w.Animated.timing(r,{toValue:0,duration:180,useNativeDriver:!0});return d.start(({finished:c})=>{c&&a(!1)}),()=>d.stop()},[e,r]),o?(0,M.jsx)(w.Animated.View,{style:[w.StyleSheet.absoluteFill,{opacity:r}],pointerEvents:t?"auto":"none",children:n}):null},Ee=({app:e,is_dark:t,status:n,progress:r,retry:o})=>{let a=t?"#FAFAFA":"#18181B";return(0,M.jsxs)(w.View,{style:[k.splash,{backgroundColor:t?"#09090B":"#FFFFFF"}],children:[(0,M.jsx)(w.View,{style:[k.splash_icon,{backgroundColor:t?"#18181B":"#F4F4F5"}],children:e.icon?(0,M.jsx)(w.Image,{source:{uri:e.icon},style:k.splash_icon_image}):(0,M.jsx)(w.Text,{style:k.splash_letter,children:(e.name||"?").slice(0,1).toUpperCase()})}),(0,M.jsx)(w.Text,{style:[k.splash_name,{color:a}],children:e.name}),n==="error"?(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(w.Text,{style:k.splash_hint,children:"Kh\xF4ng t\u1EA3i \u0111\u01B0\u1EE3c mini app"}),(0,M.jsx)(w.TouchableOpacity,{activeOpacity:.7,style:[k.retry_button,{backgroundColor:t?"#27272A":"#F4F4F5"}],onPress:o,children:(0,M.jsx)(w.Text,{style:[k.retry_text,{color:a}],children:"Th\u1EED l\u1EA1i"})})]}):(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(w.ActivityIndicator,{style:k.splash_spinner,color:t?"#A1A1AA":"#71717A"}),n==="downloading"&&(0,M.jsxs)(w.Text,{style:k.splash_hint,children:["\u0110ang t\u1EA3i mini app",r?` ${Math.round(r*100)}%`:"\u2026"]})]})]})},At=(e,t)=>{let n=(0,u.useRef)(t),r=(0,u.useRef)(!1);__DEV__&&!r.current&&n.current!==t&&(r.current=!0,console.warn(`[miniapp] MiniAppHost prop "${e}" \u0111\u1ED5i gi\u1EEFa c\xE1c l\u1EA7n render \u2192 m\u1ECDi WebView b\u1ECB mount l\u1EA1i. Khai b\xE1o component b\xEAn ngo\xE0i render.`))},Ut=({container:e,splash:t=Ee,is_dark:n=!1,bridge:r,close_on_back:o=!0,onWebLoadEnd:a})=>{At("container",e),At("splash",t);let d=e,c=J($,p=>p.active_key),i=J($,p=>Object.keys(p.instances).join("|")),f=J($,p=>{var l;return p.active_key?(l=p.instances[p.active_key])==null?void 0:l.app.name:void 0}),h=(0,u.useMemo)(()=>i?i.split("|"):[],[i]),[g,b]=(0,u.useState)({}),A=(0,u.useRef)(Wt()).current;(0,u.useEffect)(()=>{if(!c||!o)return;let p=w.BackHandler.addEventListener("hardwareBackPress",()=>(z(),!0));return()=>p.remove()},[c,o]);let T=(0,u.useCallback)(()=>{let p=$.getState().active_key;p&&b(l=>({...l,[p]:(l[p]||0)+1}))},[]);return h.length?(0,M.jsx)(d,{visible:!!c,title:f!=null?f:"",is_dark:n,close:z,reload:T,subscribeWebAtTop:A.subscribe,children:h.map(p=>(0,M.jsx)(Ht,{instance_key:p,is_active:c===p,is_dark:n,reload_tick:g[p]||0,web_at_top:A,splash:t,bridge:r,onWebLoadEnd:a},p))}):null},k=w.StyleSheet.create({webview:{flex:1,backgroundColor:"transparent"},behind:{zIndex:-1},splash:{flex:1,alignItems:"center",justifyContent:"center",gap:12},splash_icon:{width:72,height:72,borderRadius:20,alignItems:"center",justifyContent:"center",overflow:"hidden"},splash_icon_image:{width:72,height:72},splash_letter:{fontSize:28,fontWeight:"700",color:"#1D4ED8"},splash_name:{fontSize:16,fontWeight:"600"},splash_hint:{color:"#71717A"},splash_spinner:{marginTop:8},retry_button:{marginTop:4,paddingHorizontal:20,paddingVertical:10,borderRadius:999},retry_text:{fontWeight:"600"}}),Mt=u.default.memo(Ut);0&&(module.exports={DefaultMiniAppSplash,MiniAppHost,MiniAppHostError,closeMiniApp,configureMiniApp,createMmkvStorage,createRnfsFileSystem,ensureMiniApp,getLocalMiniApp,getMiniAppCatalogEntry,openMiniApp,pauseMiniAppDownloads,preloadMiniApp,resumeMiniAppDownloads,sendEventToWeb,syncMiniAppCatalog,useMiniAppDownload,useMiniAppDownloadsPaused});
45
+ true;`},at={partner:"partner_token",chatbox:"chatbox_token"},pt=(e,t)=>{let n={...e};for(let r of Object.values(at))t.includes(r)||delete n[r];return n},Re=new Set,Ge=async(e,t)=>{if(Re.has(e))throw new E("BUSY",`${e} \u0111ang ch\u1EA1y \u2014 ch\u1EDD l\u01B0\u1EE3t tr\u01B0\u1EDBc xong`);Re.add(e);try{return await t()}finally{Re.delete(e)}},Pe=(e,t)=>{if(typeof e!="string"||!e)throw new E("INVALID_PARAMS",`Thi\u1EBFu ${t}`);return e},ct=async({method:e,params:t},{getHostData:n,getPermissions:r,is_dark:s,close:o,app_id:l,instance_id:i,options:p})=>{var M,g,D,S;let f=p==null?void 0:p.handlers,A={app_id:l,instance_id:i,close:o},y=()=>new E("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF \u1EE9ng d\u1EE5ng n\xE0y`);switch(e){case"requestPayment":{let d=f==null?void 0:f.requestPayment;if(!d)throw y();let a=t==null?void 0:t.amount;if(typeof a!="number"||!Number.isFinite(a)||a<=0)throw new E("INVALID_PARAMS","amount ph\u1EA3i l\xE0 s\u1ED1 > 0");let R={...t,amount:a,currency:Pe(t==null?void 0:t.currency,"currency")};return Ge(e,()=>d(R,A))}case"printImage":{let d=f==null?void 0:f.printImage;if(!d)throw y();let a=Pe(t==null?void 0:t.image,"image");await Ge(e,()=>d({image:a},A));return}case"openScreen":if(!(f!=null&&f.openScreen))throw y();await f.openScreen({screen:Pe(t==null?void 0:t.screen,"screen"),params:t==null?void 0:t.params},A);return;case"closeApp":o();return;case"openWebview":{let d=String((M=t==null?void 0:t.url)!=null?M:"");if(!/^https?:\/\//i.test(d))throw new E("INVALID_PARAMS","url ph\u1EA3i l\xE0 http(s)");await(p!=null&&p.openUrl?p.openUrl(d):de.Linking.openURL(d));return}case"showToast":(D=p==null?void 0:p.showToast)==null||D.call(p,String((g=t==null?void 0:t.message)!=null?g:""));return;case"getSystemInfo":return{platform:de.Platform.OS==="ios"?"ios":"android",appVersion:(S=p==null?void 0:p.app_version)!=null?S:"",theme:s?"dark":"light"};case"getAccessToken":{let d=n().access_token;if(!d)throw new E("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return d}case"getToken":{let d=t==null?void 0:t.type;if(d==="access"){let q=n().access_token;if(!q)throw new E("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return q}if(d!=="partner"&&d!=="chatbox")throw new E("HOST_ERROR",`Lo\u1EA1i token kh\xF4ng h\u1EE3p l\u1EC7: ${String(d)}`);let a=at[d];if(!r().includes(a))throw new E("PERMISSION_DENIED",`Mini app ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5p quy\u1EC1n ${a} (Console \u2192 Quy\u1EC1n l\u1EA5y token)`);let R=d==="partner"?n().partner_token:n().chatbox_token;if(!R)throw new E("HOST_ERROR",`Kh\xF4ng c\xF3 ${a}`);return R}case"getUserInfo":{let d=n().user;if(!d)throw new E("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin nh\xE2n vi\xEAn");return d}case"getPageInfo":{let d=n().page;if(!d)throw new E("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin page");return d}case"sendMessage":case"insertText":throw new E("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF phi\xEAn b\u1EA3n app n\xE0y`);default:throw new E("NOT_SUPPORTED",`API kh\xF4ng t\u1ED3n t\u1EA1i: ${e}`)}};var Oe=e=>`bundle:${e}`,ke=()=>`${x().file_system.document_dir}/miniapps`,dt=(e,t,n="index.html",r=!1,s=[])=>{let o=`${ke()}/${e}/${t}`;return{app_id:e,version:t,dir:o,entry_uri:`file://${o}/${n}`,context_update:r,permissions:s}},lt=e=>{var t;x().storage.setString(Oe(e.app_id),JSON.stringify({version:e.version,entry:e.entry,context_update:!!e.context_update,permissions:(t=e.permissions)!=null?t:[]}))},Gt=(e,t)=>/^https?:\/\//.test(t)?t:`${e.replace(/[^/]*$/,"")}${t}`,T=e=>{let t=x().storage.getString(Oe(e));if(!t)return null;try{let{version:n,entry:r,context_update:s,permissions:o}=JSON.parse(t);return dt(e,n,r,!!s,Array.isArray(o)?o:[])}catch{return null}},he=e=>x().file_system.exists(e.entry_uri.replace("file://","")),Ie=async e=>{let t=T(e.app_id);return(t==null?void 0:t.version)===e.version&&await he(t)},Xt=async(e,t)=>{let n=x().file_system,r=`${ke()}/${e}`,s=await n.listDir(r).catch(()=>[]);await Promise.all(s.filter(o=>!t.includes(o)).map(o=>n.remove(`${r}/${o}`).catch(()=>{})))},gt=async e=>{var t;await((t=se[e])==null?void 0:t.catch(()=>{})),x().storage.setString(Oe(e),""),await x().file_system.remove(`${ke()}/${e}`).catch(()=>{})},Z=class extends Error{constructor(){super("cancelled"),this.name="MiniAppInstallCancelled"}},se={},De=(e,{base_url:t,onProgress:n}={})=>{var M;let r=x().file_system,s=null,o=!1,l=`${r.cache_dir}/${e.app_id}-${e.version}.zip`,i=()=>{if(o)throw new Z},p=async()=>{var S;i();let g=T(e.app_id);if((g==null?void 0:g.version)===e.version&&await r.exists(g.dir))return lt(e),T(e.app_id);i();let D=r.download({url:t?Gt(t,e.bundle_url):e.bundle_url,to_file:l,onProgress:(d,a)=>{var q;let R=a>0?a:(q=e.size)!=null?q:0;R>0&&(n==null||n(Math.min(1,d/R)))}});s=D;try{let{status:d}=await D.promise;if(i(),d!==200)throw new Error(`bundle ${d}`);if(e.sha256)if(r.sha256){if(await r.sha256(l)!==e.sha256)throw new Error("sha256 mismatch")}else J("b\u1ECF qua ki\u1EC3m tra sha256 (file_system kh\xF4ng c\xF3 sha256)",e.app_id);i();let a=dt(e.app_id,e.version,e.entry,!!e.context_update,(S=e.permissions)!=null?S:[]);return await r.remove(a.dir).catch(()=>{}),await r.mkdir(a.dir),await r.unzip(l,a.dir),lt(e),Xt(e.app_id,[e.version,g==null?void 0:g.version].filter(Boolean)),a}catch(d){throw o?new Z:d}finally{s=null,r.remove(l).catch(()=>{})}},A=((M=se[e.app_id])!=null?M:Promise.resolve()).catch(()=>{}).then(p),y=A.catch(()=>{});return se[e.app_id]=y,y.then(()=>{se[e.app_id]===y&&delete se[e.app_id]}),{promise:A,cancel:()=>{o=!0,s==null||s.cancel()}}},oe={},Zt=__DEV__?0:60*1e3,ut={},ft=(e,t)=>{var r,s;let n=T(e);return n&&Date.now()-((r=ut[t])!=null?r:0)<Zt?Promise.resolve(n):((s=oe[e])!=null||(oe[e]=(async()=>{let o=await fetch(t,{headers:{"Cache-Control":"no-cache"}});if(!o.ok)throw new Error(`manifest ${o.status}`);let l=await o.json(),i=await De(l,{base_url:t}).promise;return ut[t]=Date.now(),i})().catch(o=>(console.warn("[miniapp] sync failed",e,o==null?void 0:o.message),T(e))).finally(()=>{oe[e]=void 0})),oe[e])};var Ae=new Map,ht=(e,t)=>(Ae.set(e,t),()=>{Ae.get(e)===t&&Ae.delete(e)}),At=(e,t)=>{let n=Ae.get(e);return n?n(t):!1};var me=require("react"),Me=e=>{let t=e,n=new Set;return{getState:()=>t,setState:r=>{let s=typeof r=="function"?r(t):r;t={...t,...s},n.forEach(o=>o())},subscribe:r=>(n.add(r),()=>{n.delete(r)})}},W=(e,t,n=Object.is)=>{let r=(0,me.useRef)(null),s=()=>{let o=e.getState(),l=r.current;if(l&&l.state===o&&l.selector===t)return l.value;let i=t(o),p=l&&n(l.value,i)?l.value:i;return r.current={state:o,selector:t,value:p},p};return(0,me.useSyncExternalStore)(e.subscribe,s)};var N=Me({active_key:null,instances:{}}),mt=({app:e,instance_id:t,context:n={},url_params:r={},host_data:s={}},o)=>{var i;let l=(i=x().keep_alive)==null?void 0:i.max_webviews;N.setState(p=>{let f=t!=null?t:e.app_id,A={...p.instances,[f]:{key:f,app:e,context:n,url_params:r,host_data:s,last_used_at:Date.now()}},y=Object.keys(A);return l&&l>0&&y.length>l&&y.filter(M=>M!==f).sort((M,g)=>A[M].last_used_at-A[g].last_used_at).slice(0,y.length-l).forEach(M=>{delete A[M]}),o?{active_key:f,instances:A}:{instances:A}})},Mt=e=>mt(e,!0),wt=e=>mt(e,!1),ee=()=>N.setState({active_key:null}),we=e=>{N.setState(t=>{if(t.active_key===e||!t.instances[e])return{};let n={...t.instances};return delete n[e],{instances:n}})};var yt="catalog",en="paused_apps",tn="removed_apps",nn=10*1e3,rn=2,on=3e3,sn=()=>{var e;try{return JSON.parse((e=x().storage.getString(yt))!=null?e:"{}")}catch{return{}}},b=Me({catalog:{},downloads:{},pause_reasons:[]}),vt=e=>{let t=new Set,n=()=>x().storage.setString(e,JSON.stringify([...t]));return{has:r=>t.has(r),values:()=>[...t],add:r=>t.has(r)?!1:(t.add(r),n(),!0),delete:r=>t.delete(r)?(n(),!0):!1,load:()=>{var r;t.clear();try{let s=JSON.parse((r=x().storage.getString(e))!=null?r:"[]");Array.isArray(s)&&s.forEach(o=>{typeof o=="string"&&t.add(o)})}catch{}}}},F=vt(en),K=vt(tn);ze(()=>{F.load(),K.load();let e=sn(),t={};Object.keys(e).filter(n=>!K.has(n)).forEach(n=>{let r=T(n);r?t[n]={status:"installed",progress:1,version:r.version,has_local:!0}:F.has(n)&&(t[n]={status:"paused",progress:0,version:e[n].version,has_local:!1})}),b.setState({catalog:e,downloads:t})});var Se=e=>W(b,t=>e?t.downloads[e]:void 0),St=()=>W(b,e=>e.pause_reasons.length>0),V=(...e)=>J("queue",...e),P=[],j={},m=null,ye=new Set,G={},Le=new Set,X=e=>{Le.forEach(t=>{try{t(e)}catch(n){console.warn("[miniapp-queue] event listener error",n==null?void 0:n.message)}})},_t=e=>(Le.add(e),()=>{Le.delete(e)}),bt=()=>b.getState().downloads,k=(e,t)=>{let n=!!T(e),r=b.getState().downloads[e],s=t.status==="downloading"&&n?"updating":t.status,o={...r!=null?r:{status:"queued",progress:0},...t,...s?{status:s}:{},has_local:n};b.setState(l=>({downloads:{...l.downloads,[e]:o}})),(r==null?void 0:r.status)!==o.status||(r==null?void 0:r.version)!==o.version||(r==null?void 0:r.has_local)!==o.has_local?X({type:"status_change",app_id:e,state:o}):r.progress!==o.progress&&X({type:"progress",app_id:e,progress:o.progress,version:o.version})},ve=(e,t)=>{var n;(n=G[e])==null||n.forEach(r=>r(t)),delete G[e]},an=()=>b.getState().pause_reasons.length>0,U=e=>{var i;if(m)return;let t=e?P.indexOf(e):an()?-1:P.findIndex(p=>!F.has(p));if(t<0||t>=P.length)return;let[n]=P.splice(t,1),r=b.getState().catalog[n];if(!r){ve(n,T(n)),U();return}let s=Date.now();j[n]=((i=j[n])!=null?i:0)+1,k(n,{status:"downloading",progress:0,version:r.version,error:void 0});let o=0,l=De(r,{onProgress:p=>{let f=Math.floor(p*100);f!==o&&(o=f,k(n,{progress:f/100,version:r.version}))}});m={app_id:n,handle:l,forced:!!e},V("start",n,r.version,e?"(forced)":""),l.promise.then(p=>{V("installed",n,r.version,`${Date.now()-s}ms`),k(n,{status:"installed",progress:1,version:r.version}),ve(n,p)}).catch(p=>{var A;if(p instanceof Z){if(ye.has(n))return;V("paused",n),j[n]-=1,P.unshift(n),k(n,{status:F.has(n)?"paused":"queued",progress:0,version:r.version});return}let f=String((A=p==null?void 0:p.message)!=null?A:p);if(console.warn("[miniapp-queue] failed",n,f),j[n]<rn){k(n,{status:"queued",progress:0,version:r.version,error:f}),setTimeout(()=>{var y;P.includes(n)||(m==null?void 0:m.app_id)===n||(P.push(n),U((y=G[n])!=null&&y.length?n:void 0))},on);return}k(n,{status:"failed",progress:0,version:r.version,error:f}),ve(n,T(n))}).finally(()=>{m=null;let p=P.find(f=>{var A;return(A=G[f])==null?void 0:A.length});U(p)})},_e=(e,{front:t=!1}={})=>{if((m==null?void 0:m.app_id)===e)return;let n=P.indexOf(e);if(n>=0){if(!t)return;P.splice(n,1)}t?P.unshift(e):P.push(e)},pn=async e=>{let{host_id:t,client_token:n}=x(),r=new AbortController,s=setTimeout(()=>r.abort(),nn);try{let o=`${ue}/api/hosts/${encodeURIComponent(t)}/miniapps?channel=${e}`,l=await fetch(o,{headers:{Authorization:`Bearer ${n}`,"Cache-Control":"no-cache"},signal:r.signal});if(!l.ok)throw new Error(`host list ${e} ${l.status}`);return(await l.json()).apps.map(p=>({...p,channel:e}))}finally{clearTimeout(s)}},ie=null,be=()=>(ie!=null||(ie=(async()=>{var t;let e=Date.now();try{let n=await Promise.all(x().channels.map(pn)),r={};[...n].reverse().flat().forEach(i=>{r[i.app_id]=i});let s=Object.keys(b.getState().catalog).filter(i=>!r[i]);x().storage.setString(yt,JSON.stringify(r)),b.setState({catalog:r}),await Promise.all(s.map(i=>xt(i,{by_user:!1}))),s.forEach(i=>K.delete(i));let o=Object.keys(r).filter(i=>!K.has(i)),l=[];for(let i of o.map(p=>r[p]))await Ie(i)?k(i.app_id,{status:"installed",progress:1,version:i.version}):l.push(i);return l.forEach(i=>{j[i.app_id]=0,k(i.app_id,{status:F.has(i.app_id)?"paused":"queued",progress:0,version:i.version,error:void 0}),_e(i.app_id)}),V("catalog",o.length,"apps, outdated",l.map(i=>i.app_id),"removed",s,`${Date.now()-e}ms`),X({type:"sync_complete",app_ids:o,removed:s}),U(),{ok:!0,app_ids:o,removed:s}}catch(n){let r=String((n==null?void 0:n.name)==="AbortError"?"timeout":(t=n==null?void 0:n.message)!=null?t:n);return console.warn("[miniapp-queue] sync catalog failed",r),X({type:"sync_failed",error:r}),{ok:!1,error:r}}finally{ie=null}})()),ie),xt=async(e,{by_user:t})=>{var s,o,l,i;if(t&&K.add(e),ye.has(e))return;ye.add(e),F.delete(e);let n=P.indexOf(e);n>=0&&P.splice(n,1),(m==null?void 0:m.app_id)===e&&m.handle.cancel();let r=(i=(l=(s=b.getState().downloads[e])==null?void 0:s.version)!=null?l:(o=T(e))==null?void 0:o.version)!=null?i:"";k(e,{status:"uninstalling",progress:0,version:r}),await gt(e),we(e),b.setState(p=>{let f={...p.downloads};return delete f[e],{downloads:f}}),delete j[e],ye.delete(e),ve(e,null),V("uninstalled",e,t?"(user)":"(not in list)"),X({type:"uninstalled",app_id:e})},Et=e=>xt(e,{by_user:!0}),Tt=e=>{let t=ae(e);return t?(K.delete(e),(m==null?void 0:m.app_id)===e||P.includes(e)||(j[e]=0,k(e,{status:F.has(e)?"paused":"queued",progress:0,version:t.version,error:void 0}),_e(e),U(),V("restore",e)),!0):!1},Rt=e=>{if(F.has(e))return;if(F.add(e),V("pause app",e),(m==null?void 0:m.app_id)===e&&!m.forced){m.handle.cancel();return}let t=b.getState().downloads[e];P.includes(e)&&t&&k(e,{status:"paused",progress:0,version:t.version})},Pt=e=>{if(!F.delete(e))return;V("resume app",e);let t=b.getState().downloads[e];(t==null?void 0:t.status)==="paused"&&!P.includes(e)&&ae(e)&&(j[e]=0,_e(e)),P.includes(e)&&t&&k(e,{status:"queued",progress:0,version:t.version}),U()},Ct=e=>{let{pause_reasons:t}=b.getState();t.includes(e)||(b.setState({pause_reasons:[...t,e]}),V("pause",e),t.length===0&&X({type:"pause_change",paused:!0,reasons:[e]}),m&&!m.forced&&m.handle.cancel())},Ot=e=>{let{pause_reasons:t}=b.getState();if(!t.includes(e))return;let n=t.filter(r=>r!==e);b.setState({pause_reasons:n}),V("resume",e),n.length===0&&X({type:"pause_change",paused:!1,reasons:n}),U()},kt=()=>Object.values(b.getState().catalog).map(e=>({...e,installed:!!T(e.app_id),removed_by_user:K.has(e.app_id)})),ae=e=>b.getState().catalog[e],xe=async e=>{let t=ae(e);if(!t)return;if(F.delete(e),K.delete(e),await Ie(t))return T(e);let n=new Promise(r=>{var s;((s=G[e])!=null?s:G[e]=[]).push(r)});return(m==null?void 0:m.app_id)===e?m.forced=!0:(j[e]=0,_e(e,{front:!0}),m&&!m.forced?m.handle.cancel():U(e)),n};var v=require("react/jsx-runtime"),$e=e=>(e!=null?e:"").replace(/\?[^#]*/,""),It=0,cn=()=>{let e=new Set;return{emit:t=>e.forEach(n=>n(t)),subscribe:t=>(e.add(t),()=>{e.delete(t)})}},ln=u.default.memo(({instance_key:e,is_active:t,is_front:n,is_dark:r,reload_tick:s,web_at_top:o,splash:l,bridge:i,opaque_background:p,onWebLoadEnd:f})=>{var We,je;let A=(0,u.useRef)(null),y=(0,u.useRef)(!1),M=W(N,c=>c.instances[e]),g=M==null?void 0:M.app.app_id,D=M==null?void 0:M.app.manifest_url,S=M==null?void 0:M.context,d=M==null?void 0:M.url_params,[a,R]=(0,u.useState)(()=>g?T(g):null),[q,te]=(0,u.useState)(!1),[Nt,Fe]=(0,u.useState)(0),[Ft,ne]=(0,u.useState)(0),[Bt,L]=(0,u.useState)(!1),B=(0,u.useRef)(null),Be=c=>{B.current&&clearTimeout(B.current),B.current=setTimeout(()=>{B.current=null,L(!0)},c)};(0,u.useEffect)(()=>()=>{B.current&&clearTimeout(B.current)},[]),(0,u.useEffect)(()=>{if(!g||!t&&a)return;let c=!0;return te(!1),(async()=>{let h=T(g),C=h?await he(h):!1;if(!c||(R(C?$=>!$||$.version!==h.version||$.permissions.join(",")!==h.permissions.join(",")?h:$:null),__DEV__&&Date.now()-It>1e4&&(It=Date.now(),await be()),!c))return;let H=await xe(g),z=H!==void 0?H:D?await ft(g,D):T(g);if(c){if(!z){te(!0);return}R($=>$!=null?$:z)}})(),()=>{c=!1}},[t,g,D,Nt]),(0,u.useEffect)(()=>ht(e,c=>A.current?(A.current.postMessage(c),!0):!1),[e]);let Jt=W(b,c=>{let h=g?c.downloads[g]:void 0;return(h==null?void 0:h.status)==="installed"?h.version:void 0});(0,u.useEffect)(()=>{if(t||!g||!a)return;let c=T(g);if(!c||c.version===a.version)return;let h=!0;return he(c).then(C=>{!h||!C||(J(`webview:${e}`,"\u0111\u1ED5i bundle (\u1EA9n)",a.version,"\u2192",c.version),R(c))}),()=>{h=!1}},[t,g,Jt,a==null?void 0:a.version]),(0,u.useEffect)(()=>{var C;let c=(C=x().keep_alive)==null?void 0:C.idle_close_ms;if(t||!c||c<=0)return;let h=setTimeout(()=>{we(e)},c);return()=>clearTimeout(h)},[t,e]),(0,u.useEffect)(()=>{s>0&&(te(!1),L(!1),ne(c=>c+1),Fe(c=>c+1))},[s]);let Je=(0,u.useRef)(t);(0,u.useEffect)(()=>{var c;Je.current!==t&&(Je.current=t,y.current&&((c=A.current)==null||c.injectJavaScript(rt(t?"resumed":"paused"))))},[t]);let pe=`${(We=a==null?void 0:a.version)!=null?We:"none"}:${(je=a==null?void 0:a.permissions.join(","))!=null?je:""}:${Ft}`,re=(0,u.useMemo)(()=>JSON.stringify([S!=null?S:{},d!=null?d:{}]),[S,d]),Ee=(0,u.useMemo)(()=>{var c;return pt(d!=null?d:{},(c=a==null?void 0:a.permissions)!=null?c:[])},[re,a==null?void 0:a.permissions]),Vt=(0,u.useMemo)(()=>it(S!=null?S:{},Ee)+nt()+(x().debug?tt():""),[Ee]),ce=(0,u.useRef)(null),Ve=(0,u.useRef)(null);(0,u.useEffect)(()=>{var h,C,H;if(!a)return;if(Ve.current!==pe){Ve.current=pe,ce.current=re;return}if(ce.current===re)return;let c=((C=JSON.parse((h=ce.current)!=null?h:"[]")[0])!=null?C:{}).org_id;if(ce.current=re,c===(S==null?void 0:S.org_id)&&y.current){L(!1),Be(1500),(H=A.current)==null||H.injectJavaScript(ot(S!=null?S:{},Ee));return}L(!1),ne(z=>z+1)},[re,a,pe]);let Wt=(0,u.useCallback)(async c=>{var C,H,z,$,Te;let h=Xe(c.nativeEvent.data);if(!h){if(g&&(i!=null&&i.onWebEvent))try{Promise.resolve(i.onWebEvent(c.nativeEvent.data,{app_id:g,instance_id:e})).catch(_=>{console.warn("[miniapp] onWebEvent l\u1ED7i",g,_)})}catch(_){console.warn("[miniapp] onWebEvent l\u1ED7i",g,_)}return}if(h.method==="log"){let{level:_,text:O}=h;J(`web:${e}`,_!=null?_:"log",O!=null?O:"");return}if(h.method==="pong"){B.current||L(!0);return}if(h.method==="touchAtTop"){o.emit(!!h.at_top);return}if(h.method==="contextApplied"){B.current&&clearTimeout(B.current),B.current=null,L(!0);return}if(h.method==="ready"){y.current=!0,L(!0);let _=(C=N.getState().instances[e])==null?void 0:C.context;_&&((H=A.current)==null||H.injectJavaScript(Ce(_)));return}try{let _=await ct(h,{getHostData:()=>{var O,Y;return(Y=(O=N.getState().instances[e])==null?void 0:O.host_data)!=null?Y:{}},getPermissions:()=>{var O,Y;return g?(Y=(O=T(g))==null?void 0:O.permissions)!=null?Y:[]:[]},is_dark:r,close:ee,app_id:g!=null?g:"",instance_id:e,options:i});h.id&&((z=A.current)==null||z.injectJavaScript(Ze(h.id,_)))}catch(_){if(!h.id)return;let O=_==null?void 0:_.code,Y=_ instanceof E?_:new E(typeof O=="string"?O:"HOST_ERROR",String(($=_==null?void 0:_.message)!=null?$:_));(Te=A.current)==null||Te.injectJavaScript(et(h.id,Y))}},[e,r,g,o,i]),jt=(0,u.useCallback)(()=>{te(!1),ne(c=>c+1),Fe(c=>c+1)},[]);return(0,v.jsxs)(w.View,{style:[w.StyleSheet.absoluteFill,p&&{backgroundColor:r?"#09090B":"#FFFFFF"},!n&&I.behind],pointerEvents:t?"auto":"none",children:[a?(0,v.jsx)(Lt.default,{ref:A,source:{uri:a.entry_uri},originWhitelist:["*"],allowingReadAccessToURL:`file://${a.dir}`,allowFileAccess:!0,allowFileAccessFromFileURLs:!0,allowUniversalAccessFromFileURLs:!0,injectedJavaScriptBeforeContentLoaded:Vt,onMessage:Wt,bounces:!1,overScrollMode:"never",onLoadStart:c=>{J(`webview:${e}`,"load start",$e(c.nativeEvent.url)),y.current=!1,L(!1)},onError:c=>{J(`webview:${e}`,"load error",$e(c.nativeEvent.url),c.nativeEvent.description),te(!0),L(!1)},onLoadEnd:c=>{let h=c.nativeEvent.url;J(`webview:${e}`,"load end",$e(h)),g&&(f==null||f({app_id:g,instance_id:e,url:h})),Be(1500)},onContentProcessDidTerminate:()=>{y.current=!1,L(!1),ne(c=>c+1)},onRenderProcessGone:()=>(y.current=!1,L(!1),ne(c=>c+1),!0),style:I.webview},pe):null,M&&(0,v.jsx)(dn,{visible:!a||!Bt,interactive:q,children:(0,v.jsx)(un,{splash:l,app:M.app,is_dark:r,error:q,has_bundle:!!a,retry:jt})})]})}),un=u.default.memo(({splash:e,app:t,is_dark:n,error:r,has_bundle:s,retry:o})=>{let l=e,i=Se(t.app_id),p=r?"error":!s&&(i==null?void 0:i.status)==="downloading"?"downloading":"loading";return(0,v.jsx)(l,{app:t,is_dark:n,status:p,progress:p==="downloading"?i==null?void 0:i.progress:void 0,retry:o})}),dn=({visible:e,interactive:t,children:n})=>{let r=(0,u.useRef)(new w.Animated.Value(e?1:0)).current,[s,o]=(0,u.useState)(e);return(0,u.useEffect)(()=>{if(e){o(!0),r.setValue(1);return}let l=w.Animated.timing(r,{toValue:0,duration:180,useNativeDriver:!0});return l.start(({finished:i})=>{i&&o(!1)}),()=>l.stop()},[e,r]),s?(0,v.jsx)(w.Animated.View,{style:[w.StyleSheet.absoluteFill,{opacity:r}],pointerEvents:t?"auto":"none",children:n}):null},Ne=({app:e,is_dark:t,status:n,progress:r,retry:s})=>{let o=t?"#FAFAFA":"#18181B";return(0,v.jsxs)(w.View,{style:[I.splash,{backgroundColor:t?"#09090B":"#FFFFFF"}],children:[(0,v.jsx)(w.View,{style:[I.splash_icon,{backgroundColor:t?"#18181B":"#F4F4F5"}],children:e.icon?(0,v.jsx)(w.Image,{source:{uri:e.icon},style:I.splash_icon_image}):(0,v.jsx)(w.Text,{style:I.splash_letter,children:(e.name||"?").slice(0,1).toUpperCase()})}),(0,v.jsx)(w.Text,{style:[I.splash_name,{color:o}],children:e.name}),n==="error"?(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(w.Text,{style:I.splash_hint,children:"Kh\xF4ng t\u1EA3i \u0111\u01B0\u1EE3c mini app"}),(0,v.jsx)(w.TouchableOpacity,{activeOpacity:.7,style:[I.retry_button,{backgroundColor:t?"#27272A":"#F4F4F5"}],onPress:s,children:(0,v.jsx)(w.Text,{style:[I.retry_text,{color:o}],children:"Th\u1EED l\u1EA1i"})})]}):(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(w.ActivityIndicator,{style:I.splash_spinner,color:t?"#A1A1AA":"#71717A"}),n==="downloading"&&(0,v.jsxs)(w.Text,{style:I.splash_hint,children:["\u0110ang t\u1EA3i mini app",r?` ${Math.round(r*100)}%`:"\u2026"]})]})]})},Dt=(e,t)=>{let n=(0,u.useRef)(t),r=(0,u.useRef)(!1);__DEV__&&!r.current&&n.current!==t&&(r.current=!0,console.warn(`[miniapp] MiniAppHost prop "${e}" \u0111\u1ED5i gi\u1EEFa c\xE1c l\u1EA7n render \u2192 m\u1ECDi WebView b\u1ECB mount l\u1EA1i. Khai b\xE1o component b\xEAn ngo\xE0i render.`))},gn=({container:e,splash:t=Ne,is_dark:n=!1,bridge:r,close_on_back:s=!0,opaque_background:o=!0,onWebLoadEnd:l})=>{Dt("container",e),Dt("splash",t);let i=e,p=W(N,a=>a.active_key),f=(0,u.useRef)(p);p&&(f.current=p);let A=W(N,a=>Object.keys(a.instances).join("|")),y=W(N,a=>{var R;return a.active_key?(R=a.instances[a.active_key])==null?void 0:R.app.name:void 0}),M=(0,u.useMemo)(()=>A?A.split("|"):[],[A]),[g,D]=(0,u.useState)({}),S=(0,u.useRef)(cn()).current;(0,u.useEffect)(()=>{if(!p||!s)return;let a=w.BackHandler.addEventListener("hardwareBackPress",()=>(ee(),!0));return()=>a.remove()},[p,s]);let d=(0,u.useCallback)(()=>{let a=N.getState().active_key;a&&D(R=>({...R,[a]:(R[a]||0)+1}))},[]);return M.length?(0,v.jsx)(i,{visible:!!p,title:y!=null?y:"",is_dark:n,close:ee,reload:d,subscribeWebAtTop:S.subscribe,children:M.map(a=>(0,v.jsx)(ln,{instance_key:a,is_active:p===a,is_front:(p!=null?p:f.current)===a,is_dark:n,reload_tick:g[a]||0,web_at_top:S,splash:t,bridge:r,opaque_background:o,onWebLoadEnd:l},a))}):null},I=w.StyleSheet.create({webview:{flex:1,backgroundColor:"transparent"},behind:{zIndex:-1},splash:{flex:1,alignItems:"center",justifyContent:"center",gap:12},splash_icon:{width:72,height:72,borderRadius:20,alignItems:"center",justifyContent:"center",overflow:"hidden"},splash_icon_image:{width:72,height:72},splash_letter:{fontSize:28,fontWeight:"700",color:"#1D4ED8"},splash_name:{fontSize:16,fontWeight:"600"},splash_hint:{color:"#71717A"},splash_spinner:{marginTop:8},retry_button:{marginTop:4,paddingHorizontal:20,paddingVertical:10,borderRadius:999},retry_text:{fontWeight:"600"}}),$t=u.default.memo(gn);0&&(module.exports={DefaultMiniAppSplash,MINIAPP_PLATFORM_URL,MiniAppHost,MiniAppHostError,closeMiniApp,configureMiniApp,createMmkvStorage,createRnfsFileSystem,ensureMiniApp,getLocalMiniApp,getMiniAppCatalog,getMiniAppCatalogEntry,getMiniAppStatuses,onMiniAppEvent,openMiniApp,pauseMiniApp,pauseMiniAppDownloads,preloadMiniApp,restoreMiniApp,resumeMiniApp,resumeMiniAppDownloads,sendEventToWeb,syncMiniAppCatalog,uninstallMiniApp,useMiniAppDownload,useMiniAppDownloadsPaused});
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var q=null,Ne=new Set,yt=e=>{q=e,Ne.forEach(t=>t())},v=()=>{if(!q)throw new Error("[miniapp] Ch\u01B0a g\u1ECDi configureMiniApp()");return q},Be=e=>{Ne.add(e),q&&e()},L=(...e)=>{q!=null&&q.debug&&console.log("[miniapp]",...e)};var _t=(e,t)=>({document_dir:e.DocumentDirectoryPath,cache_dir:e.CachesDirectoryPath,exists:n=>e.exists(n),mkdir:n=>e.mkdir(n),remove:n=>e.unlink(n).catch(()=>{}),listDir:n=>e.readDir(n).then(r=>r.map(o=>o.name)).catch(()=>[]),sha256:n=>e.hash(n,"sha256"),unzip:async(n,r)=>{await t(n,r)},download:({url:n,to_file:r,onProgress:o})=>{let{jobId:a,promise:u}=e.downloadFile({fromUrl:n,toFile:r,progressInterval:250,begin:()=>{},progress:({bytesWritten:c,contentLength:i})=>o==null?void 0:o(c,i)});return{promise:u.then(({statusCode:c})=>({status:c})),cancel:()=>e.stopDownload(a)}}}),vt=e=>({getString:t=>e.getString(t),setString:(t,n)=>e.set(t,n)});import Ce,{useCallback as Te,useEffect as N,useMemo as ge,useRef as B,useState as K}from"react";import{ActivityIndicator as Wt,Animated as xe,BackHandler as Ht,Image as jt,StyleSheet as Pe,Text as re,TouchableOpacity as qt,View as Re}from"react-native";import Ut from"react-native-webview";import{Linking as St,Platform as bt}from"react-native";var ae=1,M=class extends Error{constructor(n,r){super(r);this.code=n}},Fe=e=>{try{let t=JSON.parse(e);return(t==null?void 0:t.__retion)===ae&&typeof t.method=="string"?t:null}catch{return null}},pe=e=>`window.__RETION_MINIAPP__ && window.__RETION_MINIAPP__.receive(${JSON.stringify(e)}); true;`,Ve=(e,t)=>pe({id:e,result:t}),We=(e,t)=>pe({id:e,error:{code:t.code,message:t.message}}),we=e=>pe({event:"context",data:e});var He=()=>`(function () {
1
+ var xe="https://retion-miniapp-platform.vercel.app",Q=null,Ye=new Set,Ot=e=>{Q=e,Ye.forEach(t=>t())},S=()=>{if(!Q)throw new Error("[miniapp] Ch\u01B0a g\u1ECDi configureMiniApp()");return Q},Qe=e=>{Ye.add(e),Q&&e()},B=(...e)=>{Q!=null&&Q.debug&&console.log("[miniapp]",...e)};var kt=(e,t)=>({document_dir:e.DocumentDirectoryPath,cache_dir:e.CachesDirectoryPath,exists:n=>e.exists(n),mkdir:n=>e.mkdir(n),remove:n=>e.unlink(n).catch(()=>{}),listDir:n=>e.readDir(n).then(r=>r.map(a=>a.name)).catch(()=>[]),sha256:n=>e.hash(n,"sha256"),unzip:async(n,r)=>{await t(n,r)},download:({url:n,to_file:r,onProgress:a})=>{let{jobId:o,promise:l}=e.downloadFile({fromUrl:n,toFile:r,progressInterval:250,begin:()=>{},progress:({bytesWritten:s,contentLength:p})=>a==null?void 0:a(s,p)});return{promise:l.then(({statusCode:s})=>({status:s})),cancel:()=>e.stopDownload(o)}}}),It=e=>({getString:t=>e.getString(t),setString:(t,n)=>e.set(t,n)});import Ve,{useCallback as Be,useEffect as V,useMemo as Se,useRef as N,useState as Z}from"react";import{ActivityIndicator as cn,Animated as Ne,BackHandler as ln,Image as un,StyleSheet as We,Text as pe,TouchableOpacity as dn,View as Je}from"react-native";import gn from"react-native-webview";import{Linking as Dt,Platform as Lt}from"react-native";var de=1,_=class extends Error{constructor(n,r){super(r);this.code=n}},Xe=e=>{try{let t=JSON.parse(e);return(t==null?void 0:t.__retion)===de&&typeof t.method=="string"?t:null}catch{return null}},ge=e=>`window.__RETION_MINIAPP__ && window.__RETION_MINIAPP__.receive(${JSON.stringify(e)}); true;`,Ze=(e,t)=>ge({id:e,result:t}),et=(e,t)=>ge({id:e,error:{code:t.code,message:t.message}}),Re=e=>ge({event:"context",data:e});var tt=()=>`(function () {
2
2
  var post = function (level, args) {
3
3
  try {
4
4
  var parts = [];
@@ -8,7 +8,7 @@ var q=null,Ne=new Set,yt=e=>{q=e,Ne.forEach(t=>t())},v=()=>{if(!q)throw new Erro
8
8
  else if (typeof a === 'object') { try { parts.push(JSON.stringify(a).slice(0, 800)); } catch (e) { parts.push(String(a)); } }
9
9
  else { parts.push(String(a)); }
10
10
  }
11
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${ae}, method: 'log', level: level, text: parts.join(' ') }));
11
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${de}, method: 'log', level: level, text: parts.join(' ') }));
12
12
  } catch (e) {}
13
13
  };
14
14
  ['log', 'info', 'warn', 'error'].forEach(function (level) {
@@ -19,7 +19,7 @@ var q=null,Ne=new Set,yt=e=>{q=e,Ne.forEach(t=>t())},v=()=>{if(!q)throw new Erro
19
19
  window.addEventListener('unhandledrejection', function (e) { post('error', ['[unhandledrejection]', e.reason]); });
20
20
  // Kh\xF4ng log query (c\xF3 th\u1EC3 ch\u1EE9a token) \u2014 ch\u1EC9 \u0111\u01B0\u1EDDng d\u1EABn + route.
21
21
  post('info', ['[page] ' + location.pathname + location.hash]);
22
- })(); true;`,je=()=>`(function () {
22
+ })(); true;`,nt=()=>`(function () {
23
23
  function atTop(el) {
24
24
  for (var n = el; n && n !== document.documentElement; n = n.parentElement) {
25
25
  if (n.scrollTop > 0) { return false; }
@@ -30,7 +30,7 @@ var q=null,Ne=new Set,yt=e=>{q=e,Ne.forEach(t=>t())},v=()=>{if(!q)throw new Erro
30
30
  function report(at_top) {
31
31
  if (at_top === last) { return; }
32
32
  last = at_top;
33
- window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${ae}, method: 'touchAtTop', at_top: at_top }));
33
+ window.ReactNativeWebView && window.ReactNativeWebView.postMessage(JSON.stringify({ __retion: ${de}, method: 'touchAtTop', at_top: at_top }));
34
34
  }
35
35
  document.addEventListener('touchstart', function (e) { report(atTop(e.target)); }, { capture: true, passive: true });
36
36
  // Cu\u1ED9n r\u1EDDi \u0111\u1EA7u trang \u2192 b\xE1o ngay, kh\xF4ng \u0111\u1EE3i l\u1EA7n ch\u1EA1m sau (tr\xE1nh host d\xF9ng gi\xE1 tr\u1ECB c\u0169 "\u0111ang \u1EDF \u0111\u1EA7u").
@@ -38,8 +38,8 @@ var q=null,Ne=new Set,yt=e=>{q=e,Ne.forEach(t=>t())},v=()=>{if(!q)throw new Erro
38
38
  var el = e.target === document ? document.documentElement : e.target;
39
39
  if (el && el.scrollTop > 0) { report(false); }
40
40
  }, { capture: true, passive: true });
41
- })(); true;`,qe=e=>pe({event:e}),Ue=(e,t)=>{let n=Ke(t);return`try { history.replaceState(history.state, '', location.pathname + ${JSON.stringify(n?`?${n}`:"")} + location.hash); } catch (e) {}
42
- ${we(e)}`},Ke=e=>Object.entries(e).filter(([,t])=>t!=null&&t!=="").map(([t,n])=>`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`).join("&"),ze=(e,t={})=>{let n=Ke(t);return`window.__RETION_MINIAPP_HOST__ = { protocol: ${ae} };
41
+ })(); true;`,rt=e=>ge({event:e}),ot=(e,t)=>{let n=st(t);return`try { history.replaceState(history.state, '', location.pathname + ${JSON.stringify(n?`?${n}`:"")} + location.hash); } catch (e) {}
42
+ ${Re(e)}`},st=e=>Object.entries(e).filter(([,t])=>t!=null&&t!=="").map(([t,n])=>`${encodeURIComponent(t)}=${encodeURIComponent(String(n))}`).join("&"),it=(e,t={})=>{let n=st(t);return`window.__RETION_MINIAPP_HOST__ = { protocol: ${de} };
43
43
  window.__RETION_MINIAPP_CONTEXT__ = ${JSON.stringify(e)};
44
44
  ${n?`try { history.replaceState(history.state, '', location.pathname + '?' + ${JSON.stringify(n)} + location.hash); } catch (e) {}`:""}
45
- true;`},Qe={partner:"partner_token",chatbox:"chatbox_token"},Ye=(e,t)=>{let n={...e};for(let r of Object.values(Qe))t.includes(r)||delete n[r];return n},me=new Set,Je=async(e,t)=>{if(me.has(e))throw new M("BUSY",`${e} \u0111ang ch\u1EA1y \u2014 ch\u1EDD l\u01B0\u1EE3t tr\u01B0\u1EDBc xong`);me.add(e);try{return await t()}finally{me.delete(e)}},Ae=(e,t)=>{if(typeof e!="string"||!e)throw new M("INVALID_PARAMS",`Thi\u1EBFu ${t}`);return e},Ge=async({method:e,params:t},{getHostData:n,getPermissions:r,is_dark:o,close:a,app_id:u,instance_id:c,options:i})=>{var _,m,b,p;let g=i==null?void 0:i.handlers,f={app_id:u,instance_id:c,close:a},d=()=>new M("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF \u1EE9ng d\u1EE5ng n\xE0y`);switch(e){case"requestPayment":{let l=g==null?void 0:g.requestPayment;if(!l)throw d();let w=t==null?void 0:t.amount;if(typeof w!="number"||!Number.isFinite(w)||w<=0)throw new M("INVALID_PARAMS","amount ph\u1EA3i l\xE0 s\u1ED1 > 0");let E={...t,amount:w,currency:Ae(t==null?void 0:t.currency,"currency")};return Je(e,()=>l(E,f))}case"printImage":{let l=g==null?void 0:g.printImage;if(!l)throw d();let w=Ae(t==null?void 0:t.image,"image");await Je(e,()=>l({image:w},f));return}case"openScreen":if(!(g!=null&&g.openScreen))throw d();await g.openScreen({screen:Ae(t==null?void 0:t.screen,"screen"),params:t==null?void 0:t.params},f);return;case"closeApp":a();return;case"openWebview":{let l=String((_=t==null?void 0:t.url)!=null?_:"");if(!/^https?:\/\//i.test(l))throw new M("INVALID_PARAMS","url ph\u1EA3i l\xE0 http(s)");await(i!=null&&i.openUrl?i.openUrl(l):St.openURL(l));return}case"showToast":(b=i==null?void 0:i.showToast)==null||b.call(i,String((m=t==null?void 0:t.message)!=null?m:""));return;case"getSystemInfo":return{platform:bt.OS==="ios"?"ios":"android",appVersion:(p=i==null?void 0:i.app_version)!=null?p:"",theme:o?"dark":"light"};case"getAccessToken":{let l=n().access_token;if(!l)throw new M("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return l}case"getToken":{let l=t==null?void 0:t.type;if(l==="access"){let W=n().access_token;if(!W)throw new M("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return W}if(l!=="partner"&&l!=="chatbox")throw new M("HOST_ERROR",`Lo\u1EA1i token kh\xF4ng h\u1EE3p l\u1EC7: ${String(l)}`);let w=Qe[l];if(!r().includes(w))throw new M("PERMISSION_DENIED",`Mini app ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5p quy\u1EC1n ${w} (Console \u2192 Quy\u1EC1n l\u1EA5y token)`);let E=l==="partner"?n().partner_token:n().chatbox_token;if(!E)throw new M("HOST_ERROR",`Kh\xF4ng c\xF3 ${w}`);return E}case"getUserInfo":{let l=n().user;if(!l)throw new M("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin nh\xE2n vi\xEAn");return l}case"getPageInfo":{let l=n().page;if(!l)throw new M("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin page");return l}case"sendMessage":case"insertText":throw new M("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF phi\xEAn b\u1EA3n app n\xE0y`);default:throw new M("NOT_SUPPORTED",`API kh\xF4ng t\u1ED3n t\u1EA1i: ${e}`)}};var et=e=>`bundle:${e}`,tt=()=>`${v().file_system.document_dir}/miniapps`,nt=(e,t,n="index.html",r=!1,o=[])=>{let a=`${tt()}/${e}/${t}`;return{app_id:e,version:t,dir:a,entry_uri:`file://${a}/${n}`,context_update:r,permissions:o}},Xe=e=>{var t;v().storage.setString(et(e.app_id),JSON.stringify({version:e.version,entry:e.entry,context_update:!!e.context_update,permissions:(t=e.permissions)!=null?t:[]}))},xt=(e,t)=>/^https?:\/\//.test(t)?t:`${e.replace(/[^/]*$/,"")}${t}`,S=e=>{let t=v().storage.getString(et(e));if(!t)return null;try{let{version:n,entry:r,context_update:o,permissions:a}=JSON.parse(t);return nt(e,n,r,!!o,Array.isArray(a)?a:[])}catch{return null}},le=e=>v().file_system.exists(e.entry_uri.replace("file://","")),Me=async e=>{let t=S(e.app_id);return(t==null?void 0:t.version)===e.version&&await le(t)},Et=async(e,t)=>{let n=v().file_system,r=`${tt()}/${e}`,o=await n.listDir(r).catch(()=>[]);await Promise.all(o.filter(a=>!t.includes(a)).map(a=>n.remove(`${r}/${a}`).catch(()=>{})))},z=class extends Error{constructor(){super("cancelled"),this.name="MiniAppInstallCancelled"}},ce={},ye=(e,{base_url:t,onProgress:n}={})=>{var _;let r=v().file_system,o=null,a=!1,u=`${r.cache_dir}/${e.app_id}-${e.version}.zip`,c=()=>{if(a)throw new z},i=async()=>{var p;c();let m=S(e.app_id);if((m==null?void 0:m.version)===e.version&&await r.exists(m.dir))return Xe(e),S(e.app_id);c();let b=r.download({url:t?xt(t,e.bundle_url):e.bundle_url,to_file:u,onProgress:(l,w)=>{var W;let E=w>0?w:(W=e.size)!=null?W:0;E>0&&(n==null||n(Math.min(1,l/E)))}});o=b;try{let{status:l}=await b.promise;if(c(),l!==200)throw new Error(`bundle ${l}`);if(e.sha256)if(r.sha256){if(await r.sha256(u)!==e.sha256)throw new Error("sha256 mismatch")}else L("b\u1ECF qua ki\u1EC3m tra sha256 (file_system kh\xF4ng c\xF3 sha256)",e.app_id);c();let w=nt(e.app_id,e.version,e.entry,!!e.context_update,(p=e.permissions)!=null?p:[]);return await r.remove(w.dir).catch(()=>{}),await r.mkdir(w.dir),await r.unzip(u,w.dir),Xe(e),Et(e.app_id,[e.version,m==null?void 0:m.version].filter(Boolean)),w}catch(l){throw a?new z:l}finally{o=null,r.remove(u).catch(()=>{})}},f=((_=ce[e.app_id])!=null?_:Promise.resolve()).catch(()=>{}).then(i),d=f.catch(()=>{});return ce[e.app_id]=d,d.then(()=>{ce[e.app_id]===d&&delete ce[e.app_id]}),{promise:f,cancel:()=>{a=!0,o==null||o.cancel()}}},ee={},Tt=__DEV__?0:60*1e3,Ze={},rt=(e,t)=>{var r,o;let n=S(e);return n&&Date.now()-((r=Ze[t])!=null?r:0)<Tt?Promise.resolve(n):((o=ee[e])!=null||(ee[e]=(async()=>{let a=await fetch(t,{headers:{"Cache-Control":"no-cache"}});if(!a.ok)throw new Error(`manifest ${a.status}`);let u=await a.json(),c=await ye(u,{base_url:t}).promise;return Ze[t]=Date.now(),c})().catch(a=>(console.warn("[miniapp] sync failed",e,a==null?void 0:a.message),S(e))).finally(()=>{ee[e]=void 0})),ee[e])};var ue=new Map,ot=(e,t)=>(ue.set(e,t),()=>{ue.get(e)===t&&ue.delete(e)}),Rt=(e,t)=>{let n=ue.get(e);return n?n(t):!1};import{useRef as Ct,useSyncExternalStore as Pt}from"react";var de=e=>{let t=e,n=new Set;return{getState:()=>t,setState:r=>{let o=typeof r=="function"?r(t):r;t={...t,...o},n.forEach(a=>a())},subscribe:r=>(n.add(r),()=>{n.delete(r)})}},J=(e,t,n=Object.is)=>{let r=Ct(null),o=()=>{let a=e.getState(),u=r.current;if(u&&u.state===a&&u.selector===t)return u.value;let c=t(a),i=u&&n(u.value,c)?u.value:c;return r.current={state:a,selector:t,value:i},i};return Pt(e.subscribe,o)};var D=de({active_key:null,instances:{}}),it=({app:e,instance_id:t,context:n={},url_params:r={},host_data:o={}},a)=>{var c;let u=(c=v().keep_alive)==null?void 0:c.max_webviews;D.setState(i=>{let g=t!=null?t:e.app_id,f={...i.instances,[g]:{key:g,app:e,context:n,url_params:r,host_data:o,last_used_at:Date.now()}},d=Object.keys(f);return u&&u>0&&d.length>u&&d.filter(_=>_!==g).sort((_,m)=>f[_].last_used_at-f[m].last_used_at).slice(0,d.length-u).forEach(_=>{delete f[_]}),a?{active_key:g,instances:f}:{instances:f}})},Ot=e=>it(e,!0),kt=e=>it(e,!1),te=()=>D.setState({active_key:null}),st=e=>{D.setState(t=>{if(t.active_key===e||!t.instances[e])return{};let n={...t.instances};return delete n[e],{instances:n}})};var at="catalog",Dt=10*1e3,It=2,$t=3e3,Lt=()=>{var e;try{return JSON.parse((e=v().storage.getString(at))!=null?e:"{}")}catch{return{}}},T=de({catalog:{},downloads:{},pause_reasons:[]});Be(()=>T.setState({catalog:Lt()}));var ve=e=>J(T,t=>e?t.downloads[e]:void 0),Nt=()=>J(T,e=>e.pause_reasons.length>0),Y=(...e)=>L("queue",...e),I=[],Q={},y=null,U={},V=(e,t)=>{T.setState(n=>{let r=n.downloads[e];return{downloads:{...n.downloads,[e]:{...r!=null?r:{status:"queued",progress:0},...t}}}})},_e=(e,t)=>{var n;(n=U[e])==null||n.forEach(r=>r(t)),delete U[e]},Bt=()=>T.getState().pause_reasons.length>0,G=e=>{var c;if(y)return;let t=e?I.indexOf(e):Bt()?-1:0;if(t<0||t>=I.length)return;let[n]=I.splice(t,1),r=T.getState().catalog[n];if(!r){_e(n,S(n)),G();return}let o=Date.now();Q[n]=((c=Q[n])!=null?c:0)+1,V(n,{status:"downloading",progress:0,version:r.version,error:void 0});let a=0,u=ye(r,{onProgress:i=>{let g=Math.floor(i*100);g!==a&&(a=g,V(n,{progress:g/100,version:r.version}))}});y={app_id:n,handle:u,forced:!!e},Y("start",n,r.version,e?"(forced)":""),u.promise.then(i=>{Y("installed",n,r.version,`${Date.now()-o}ms`),V(n,{status:"installed",progress:1,version:r.version}),_e(n,i)}).catch(i=>{var f;if(i instanceof z){Y("paused",n),Q[n]-=1,I.unshift(n),V(n,{status:"queued",progress:0,version:r.version});return}let g=String((f=i==null?void 0:i.message)!=null?f:i);if(console.warn("[miniapp-queue] failed",n,g),Q[n]<It){V(n,{status:"queued",progress:0,version:r.version,error:g}),setTimeout(()=>{var d;I.includes(n)||(y==null?void 0:y.app_id)===n||(I.push(n),G((d=U[n])!=null&&d.length?n:void 0))},$t);return}V(n,{status:"failed",progress:0,version:r.version,error:g}),_e(n,S(n))}).finally(()=>{y=null;let i=I.find(g=>{var f;return(f=U[g])==null?void 0:f.length});G(i)})},pt=(e,{front:t=!1}={})=>{if((y==null?void 0:y.app_id)===e)return;let n=I.indexOf(e);if(n>=0){if(!t)return;I.splice(n,1)}t?I.unshift(e):I.push(e)},Jt=async e=>{let{platform_url:t,host_id:n,client_token:r}=v(),o=new AbortController,a=setTimeout(()=>o.abort(),Dt);try{let u=`${t}/api/hosts/${encodeURIComponent(n)}/miniapps?channel=${e}`,c=await fetch(u,{headers:{Authorization:`Bearer ${r}`,"Cache-Control":"no-cache"},signal:o.signal});if(!c.ok)throw new Error(`host list ${e} ${c.status}`);return(await c.json()).apps.map(g=>({...g,channel:e}))}finally{clearTimeout(a)}},ne=null,Se=()=>(ne!=null||(ne=(async()=>{let e=Date.now();try{let t=await Promise.all(v().channels.map(Jt)),n={};[...t].reverse().flat().forEach(o=>{n[o.app_id]=o}),v().storage.setString(at,JSON.stringify(n)),T.setState({catalog:n});let r=[];for(let o of Object.values(n))await Me(o)?V(o.app_id,{status:"installed",progress:1,version:o.version}):r.push(o);r.forEach(o=>{Q[o.app_id]=0,V(o.app_id,{status:"queued",progress:0,version:o.version,error:void 0}),pt(o.app_id)}),Y("catalog",Object.keys(n).length,"apps, outdated",r.map(o=>o.app_id),`${Date.now()-e}ms`),G()}catch(t){console.warn("[miniapp-queue] sync catalog failed",t==null?void 0:t.message)}finally{ne=null}})()),ne),Ft=e=>{let{pause_reasons:t}=T.getState();t.includes(e)||(T.setState({pause_reasons:[...t,e]}),Y("pause",e),y&&!y.forced&&y.handle.cancel())},Vt=e=>{let{pause_reasons:t}=T.getState();t.includes(e)&&(T.setState({pause_reasons:t.filter(n=>n!==e)}),Y("resume",e),G())},ct=e=>T.getState().catalog[e],be=async e=>{let t=ct(e);if(!t)return;if(await Me(t))return S(e);let n=new Promise(r=>{var o;((o=U[e])!=null?o:U[e]=[]).push(r)});return(y==null?void 0:y.app_id)===e?y.forced=!0:(Q[e]=0,pt(e,{front:!0}),y&&!y.forced?y.handle.cancel():G(e)),n};import{Fragment as dt,jsx as x,jsxs as oe}from"react/jsx-runtime";var Ee=e=>(e!=null?e:"").replace(/\?[^#]*/,""),lt=0,Kt=()=>{let e=new Set;return{emit:t=>e.forEach(n=>n(t)),subscribe:t=>(e.add(t),()=>{e.delete(t)})}},zt=Ce.memo(({instance_key:e,is_active:t,is_dark:n,reload_tick:r,web_at_top:o,splash:a,bridge:u,onWebLoadEnd:c})=>{var $e,Le;let i=B(null),g=B(!1),f=J(D,s=>s.instances[e]),d=f==null?void 0:f.app.app_id,_=f==null?void 0:f.app.manifest_url,m=f==null?void 0:f.context,b=f==null?void 0:f.url_params,[p,l]=K(()=>d?S(d):null),[w,E]=K(!1),[W,Oe]=K(0),[ft,X]=K(0),[ht,O]=K(!1),$=B(null),ke=s=>{$.current&&clearTimeout($.current),$.current=setTimeout(()=>{$.current=null,O(!0)},s)};N(()=>()=>{$.current&&clearTimeout($.current)},[]),N(()=>{if(!d||!t&&p)return;let s=!0;return E(!1),(async()=>{let h=S(d),R=h?await le(h):!1;if(!s||(l(R?k=>!k||k.version!==h.version||k.permissions.join(",")!==h.permissions.join(",")?h:k:null),__DEV__&&Date.now()-lt>1e4&&(lt=Date.now(),await Se()),!s))return;let F=await be(d),H=F!==void 0?F:_?await rt(d,_):S(d);if(s){if(!H){E(!0);return}l(k=>k!=null?k:H)}})(),()=>{s=!1}},[t,d,_,W]),N(()=>ot(e,s=>i.current?(i.current.postMessage(s),!0):!1),[e]);let mt=J(T,s=>{let h=d?s.downloads[d]:void 0;return(h==null?void 0:h.status)==="installed"?h.version:void 0});N(()=>{if(t||!d||!p)return;let s=S(d);if(!s||s.version===p.version)return;let h=!0;return le(s).then(R=>{!h||!R||(L(`webview:${e}`,"\u0111\u1ED5i bundle (\u1EA9n)",p.version,"\u2192",s.version),l(s))}),()=>{h=!1}},[t,d,mt,p==null?void 0:p.version]),N(()=>{var R;let s=(R=v().keep_alive)==null?void 0:R.idle_close_ms;if(t||!s||s<=0)return;let h=setTimeout(()=>{st(e)},s);return()=>clearTimeout(h)},[t,e]),N(()=>{r>0&&(E(!1),O(!1),X(s=>s+1),Oe(s=>s+1))},[r]);let De=B(t);N(()=>{var s;De.current!==t&&(De.current=t,g.current&&((s=i.current)==null||s.injectJavaScript(qe(t?"resumed":"paused"))))},[t]);let ie=`${($e=p==null?void 0:p.version)!=null?$e:"none"}:${(Le=p==null?void 0:p.permissions.join(","))!=null?Le:""}:${ft}`,Z=ge(()=>JSON.stringify([m!=null?m:{},b!=null?b:{}]),[m,b]),fe=ge(()=>{var s;return Ye(b!=null?b:{},(s=p==null?void 0:p.permissions)!=null?s:[])},[Z,p==null?void 0:p.permissions]),At=ge(()=>ze(m!=null?m:{},fe)+je()+(v().debug?He():""),[fe]),se=B(null),Ie=B(null);N(()=>{var h,R,F;if(!p)return;if(Ie.current!==ie){Ie.current=ie,se.current=Z;return}if(se.current===Z)return;let s=((R=JSON.parse((h=se.current)!=null?h:"[]")[0])!=null?R:{}).org_id;if(se.current=Z,s===(m==null?void 0:m.org_id)&&g.current){O(!1),ke(1500),(F=i.current)==null||F.injectJavaScript(Ue(m!=null?m:{},fe));return}O(!1),X(H=>H+1)},[Z,p,ie]);let wt=Te(async s=>{var R,F,H,k,he;let h=Fe(s.nativeEvent.data);if(!h){if(d&&(u!=null&&u.onWebEvent))try{Promise.resolve(u.onWebEvent(s.nativeEvent.data,{app_id:d,instance_id:e})).catch(A=>{console.warn("[miniapp] onWebEvent l\u1ED7i",d,A)})}catch(A){console.warn("[miniapp] onWebEvent l\u1ED7i",d,A)}return}if(h.method==="log"){let{level:A,text:C}=h;L(`web:${e}`,A!=null?A:"log",C!=null?C:"");return}if(h.method==="pong"){$.current||O(!0);return}if(h.method==="touchAtTop"){o.emit(!!h.at_top);return}if(h.method==="contextApplied"){$.current&&clearTimeout($.current),$.current=null,O(!0);return}if(h.method==="ready"){g.current=!0,O(!0);let A=(R=D.getState().instances[e])==null?void 0:R.context;A&&((F=i.current)==null||F.injectJavaScript(we(A)));return}try{let A=await Ge(h,{getHostData:()=>{var C,j;return(j=(C=D.getState().instances[e])==null?void 0:C.host_data)!=null?j:{}},getPermissions:()=>{var C,j;return d?(j=(C=S(d))==null?void 0:C.permissions)!=null?j:[]:[]},is_dark:n,close:te,app_id:d!=null?d:"",instance_id:e,options:u});h.id&&((H=i.current)==null||H.injectJavaScript(Ve(h.id,A)))}catch(A){if(!h.id)return;let C=A==null?void 0:A.code,j=A instanceof M?A:new M(typeof C=="string"?C:"HOST_ERROR",String((k=A==null?void 0:A.message)!=null?k:A));(he=i.current)==null||he.injectJavaScript(We(h.id,j))}},[e,n,d,o,u]),Mt=Te(()=>{E(!1),X(s=>s+1),Oe(s=>s+1)},[]);return oe(Re,{style:[Pe.absoluteFill,!t&&P.behind],pointerEvents:t?"auto":"none",children:[p?x(Ut,{ref:i,source:{uri:p.entry_uri},originWhitelist:["*"],allowingReadAccessToURL:`file://${p.dir}`,allowFileAccess:!0,allowFileAccessFromFileURLs:!0,allowUniversalAccessFromFileURLs:!0,injectedJavaScriptBeforeContentLoaded:At,onMessage:wt,bounces:!1,overScrollMode:"never",onLoadStart:s=>{L(`webview:${e}`,"load start",Ee(s.nativeEvent.url)),g.current=!1,O(!1)},onError:s=>{L(`webview:${e}`,"load error",Ee(s.nativeEvent.url),s.nativeEvent.description),E(!0),O(!1)},onLoadEnd:s=>{let h=s.nativeEvent.url;L(`webview:${e}`,"load end",Ee(h)),d&&(c==null||c({app_id:d,instance_id:e,url:h})),ke(1500)},onContentProcessDidTerminate:()=>{g.current=!1,O(!1),X(s=>s+1)},onRenderProcessGone:()=>(g.current=!1,O(!1),X(s=>s+1),!0),style:P.webview},ie):null,f&&x(Yt,{visible:!p||!ht,interactive:w,children:x(Qt,{splash:a,app:f.app,is_dark:n,error:w,has_bundle:!!p,retry:Mt})})]})}),Qt=Ce.memo(({splash:e,app:t,is_dark:n,error:r,has_bundle:o,retry:a})=>{let u=e,c=ve(t.app_id),i=r?"error":!o&&(c==null?void 0:c.status)==="downloading"?"downloading":"loading";return x(u,{app:t,is_dark:n,status:i,progress:i==="downloading"?c==null?void 0:c.progress:void 0,retry:a})}),Yt=({visible:e,interactive:t,children:n})=>{let r=B(new xe.Value(e?1:0)).current,[o,a]=K(e);return N(()=>{if(e){a(!0),r.setValue(1);return}let u=xe.timing(r,{toValue:0,duration:180,useNativeDriver:!0});return u.start(({finished:c})=>{c&&a(!1)}),()=>u.stop()},[e,r]),o?x(xe.View,{style:[Pe.absoluteFill,{opacity:r}],pointerEvents:t?"auto":"none",children:n}):null},gt=({app:e,is_dark:t,status:n,progress:r,retry:o})=>{let a=t?"#FAFAFA":"#18181B";return oe(Re,{style:[P.splash,{backgroundColor:t?"#09090B":"#FFFFFF"}],children:[x(Re,{style:[P.splash_icon,{backgroundColor:t?"#18181B":"#F4F4F5"}],children:e.icon?x(jt,{source:{uri:e.icon},style:P.splash_icon_image}):x(re,{style:P.splash_letter,children:(e.name||"?").slice(0,1).toUpperCase()})}),x(re,{style:[P.splash_name,{color:a}],children:e.name}),n==="error"?oe(dt,{children:[x(re,{style:P.splash_hint,children:"Kh\xF4ng t\u1EA3i \u0111\u01B0\u1EE3c mini app"}),x(qt,{activeOpacity:.7,style:[P.retry_button,{backgroundColor:t?"#27272A":"#F4F4F5"}],onPress:o,children:x(re,{style:[P.retry_text,{color:a}],children:"Th\u1EED l\u1EA1i"})})]}):oe(dt,{children:[x(Wt,{style:P.splash_spinner,color:t?"#A1A1AA":"#71717A"}),n==="downloading"&&oe(re,{style:P.splash_hint,children:["\u0110ang t\u1EA3i mini app",r?` ${Math.round(r*100)}%`:"\u2026"]})]})]})},ut=(e,t)=>{let n=B(t),r=B(!1);__DEV__&&!r.current&&n.current!==t&&(r.current=!0,console.warn(`[miniapp] MiniAppHost prop "${e}" \u0111\u1ED5i gi\u1EEFa c\xE1c l\u1EA7n render \u2192 m\u1ECDi WebView b\u1ECB mount l\u1EA1i. Khai b\xE1o component b\xEAn ngo\xE0i render.`))},Gt=({container:e,splash:t=gt,is_dark:n=!1,bridge:r,close_on_back:o=!0,onWebLoadEnd:a})=>{ut("container",e),ut("splash",t);let u=e,c=J(D,p=>p.active_key),i=J(D,p=>Object.keys(p.instances).join("|")),g=J(D,p=>{var l;return p.active_key?(l=p.instances[p.active_key])==null?void 0:l.app.name:void 0}),f=ge(()=>i?i.split("|"):[],[i]),[d,_]=K({}),m=B(Kt()).current;N(()=>{if(!c||!o)return;let p=Ht.addEventListener("hardwareBackPress",()=>(te(),!0));return()=>p.remove()},[c,o]);let b=Te(()=>{let p=D.getState().active_key;p&&_(l=>({...l,[p]:(l[p]||0)+1}))},[]);return f.length?x(u,{visible:!!c,title:g!=null?g:"",is_dark:n,close:te,reload:b,subscribeWebAtTop:m.subscribe,children:f.map(p=>x(zt,{instance_key:p,is_active:c===p,is_dark:n,reload_tick:d[p]||0,web_at_top:m,splash:t,bridge:r,onWebLoadEnd:a},p))}):null},P=Pe.create({webview:{flex:1,backgroundColor:"transparent"},behind:{zIndex:-1},splash:{flex:1,alignItems:"center",justifyContent:"center",gap:12},splash_icon:{width:72,height:72,borderRadius:20,alignItems:"center",justifyContent:"center",overflow:"hidden"},splash_icon_image:{width:72,height:72},splash_letter:{fontSize:28,fontWeight:"700",color:"#1D4ED8"},splash_name:{fontSize:16,fontWeight:"600"},splash_hint:{color:"#71717A"},splash_spinner:{marginTop:8},retry_button:{marginTop:4,paddingHorizontal:20,paddingVertical:10,borderRadius:999},retry_text:{fontWeight:"600"}}),Xt=Ce.memo(Gt);export{gt as DefaultMiniAppSplash,Xt as MiniAppHost,M as MiniAppHostError,te as closeMiniApp,yt as configureMiniApp,vt as createMmkvStorage,_t as createRnfsFileSystem,be as ensureMiniApp,S as getLocalMiniApp,ct as getMiniAppCatalogEntry,Ot as openMiniApp,Ft as pauseMiniAppDownloads,kt as preloadMiniApp,Vt as resumeMiniAppDownloads,Rt as sendEventToWeb,Se as syncMiniAppCatalog,ve as useMiniAppDownload,Nt as useMiniAppDownloadsPaused};
45
+ true;`},at={partner:"partner_token",chatbox:"chatbox_token"},pt=(e,t)=>{let n={...e};for(let r of Object.values(at))t.includes(r)||delete n[r];return n},Ee=new Set,Ge=async(e,t)=>{if(Ee.has(e))throw new _("BUSY",`${e} \u0111ang ch\u1EA1y \u2014 ch\u1EDD l\u01B0\u1EE3t tr\u01B0\u1EDBc xong`);Ee.add(e);try{return await t()}finally{Ee.delete(e)}},Te=(e,t)=>{if(typeof e!="string"||!e)throw new _("INVALID_PARAMS",`Thi\u1EBFu ${t}`);return e},ct=async({method:e,params:t},{getHostData:n,getPermissions:r,is_dark:a,close:o,app_id:l,instance_id:s,options:p})=>{var m,d,k,w;let g=p==null?void 0:p.handlers,h={app_id:l,instance_id:s,close:o},M=()=>new _("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF \u1EE9ng d\u1EE5ng n\xE0y`);switch(e){case"requestPayment":{let u=g==null?void 0:g.requestPayment;if(!u)throw M();let i=t==null?void 0:t.amount;if(typeof i!="number"||!Number.isFinite(i)||i<=0)throw new _("INVALID_PARAMS","amount ph\u1EA3i l\xE0 s\u1ED1 > 0");let x={...t,amount:i,currency:Te(t==null?void 0:t.currency,"currency")};return Ge(e,()=>u(x,h))}case"printImage":{let u=g==null?void 0:g.printImage;if(!u)throw M();let i=Te(t==null?void 0:t.image,"image");await Ge(e,()=>u({image:i},h));return}case"openScreen":if(!(g!=null&&g.openScreen))throw M();await g.openScreen({screen:Te(t==null?void 0:t.screen,"screen"),params:t==null?void 0:t.params},h);return;case"closeApp":o();return;case"openWebview":{let u=String((m=t==null?void 0:t.url)!=null?m:"");if(!/^https?:\/\//i.test(u))throw new _("INVALID_PARAMS","url ph\u1EA3i l\xE0 http(s)");await(p!=null&&p.openUrl?p.openUrl(u):Dt.openURL(u));return}case"showToast":(k=p==null?void 0:p.showToast)==null||k.call(p,String((d=t==null?void 0:t.message)!=null?d:""));return;case"getSystemInfo":return{platform:Lt.OS==="ios"?"ios":"android",appVersion:(w=p==null?void 0:p.app_version)!=null?w:"",theme:a?"dark":"light"};case"getAccessToken":{let u=n().access_token;if(!u)throw new _("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return u}case"getToken":{let u=t==null?void 0:t.type;if(u==="access"){let q=n().access_token;if(!q)throw new _("HOST_ERROR","Mini app ch\u01B0a c\xF3 token cho page n\xE0y");return q}if(u!=="partner"&&u!=="chatbox")throw new _("HOST_ERROR",`Lo\u1EA1i token kh\xF4ng h\u1EE3p l\u1EC7: ${String(u)}`);let i=at[u];if(!r().includes(i))throw new _("PERMISSION_DENIED",`Mini app ch\u01B0a \u0111\u01B0\u1EE3c c\u1EA5p quy\u1EC1n ${i} (Console \u2192 Quy\u1EC1n l\u1EA5y token)`);let x=u==="partner"?n().partner_token:n().chatbox_token;if(!x)throw new _("HOST_ERROR",`Kh\xF4ng c\xF3 ${i}`);return x}case"getUserInfo":{let u=n().user;if(!u)throw new _("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin nh\xE2n vi\xEAn");return u}case"getPageInfo":{let u=n().page;if(!u)throw new _("HOST_ERROR","Kh\xF4ng l\u1EA5y \u0111\u01B0\u1EE3c th\xF4ng tin page");return u}case"sendMessage":case"insertText":throw new _("NOT_SUPPORTED",`${e} ch\u01B0a h\u1ED7 tr\u1EE3 \u1EDF phi\xEAn b\u1EA3n app n\xE0y`);default:throw new _("NOT_SUPPORTED",`API kh\xF4ng t\u1ED3n t\u1EA1i: ${e}`)}};var Pe=e=>`bundle:${e}`,Ce=()=>`${S().file_system.document_dir}/miniapps`,dt=(e,t,n="index.html",r=!1,a=[])=>{let o=`${Ce()}/${e}/${t}`;return{app_id:e,version:t,dir:o,entry_uri:`file://${o}/${n}`,context_update:r,permissions:a}},lt=e=>{var t;S().storage.setString(Pe(e.app_id),JSON.stringify({version:e.version,entry:e.entry,context_update:!!e.context_update,permissions:(t=e.permissions)!=null?t:[]}))},$t=(e,t)=>/^https?:\/\//.test(t)?t:`${e.replace(/[^/]*$/,"")}${t}`,b=e=>{let t=S().storage.getString(Pe(e));if(!t)return null;try{let{version:n,entry:r,context_update:a,permissions:o}=JSON.parse(t);return dt(e,n,r,!!a,Array.isArray(o)?o:[])}catch{return null}},fe=e=>S().file_system.exists(e.entry_uri.replace("file://","")),Oe=async e=>{let t=b(e.app_id);return(t==null?void 0:t.version)===e.version&&await fe(t)},Nt=async(e,t)=>{let n=S().file_system,r=`${Ce()}/${e}`,a=await n.listDir(r).catch(()=>[]);await Promise.all(a.filter(o=>!t.includes(o)).map(o=>n.remove(`${r}/${o}`).catch(()=>{})))},gt=async e=>{var t;await((t=se[e])==null?void 0:t.catch(()=>{})),S().storage.setString(Pe(e),""),await S().file_system.remove(`${Ce()}/${e}`).catch(()=>{})},ee=class extends Error{constructor(){super("cancelled"),this.name="MiniAppInstallCancelled"}},se={},ke=(e,{base_url:t,onProgress:n}={})=>{var m;let r=S().file_system,a=null,o=!1,l=`${r.cache_dir}/${e.app_id}-${e.version}.zip`,s=()=>{if(o)throw new ee},p=async()=>{var w;s();let d=b(e.app_id);if((d==null?void 0:d.version)===e.version&&await r.exists(d.dir))return lt(e),b(e.app_id);s();let k=r.download({url:t?$t(t,e.bundle_url):e.bundle_url,to_file:l,onProgress:(u,i)=>{var q;let x=i>0?i:(q=e.size)!=null?q:0;x>0&&(n==null||n(Math.min(1,u/x)))}});a=k;try{let{status:u}=await k.promise;if(s(),u!==200)throw new Error(`bundle ${u}`);if(e.sha256)if(r.sha256){if(await r.sha256(l)!==e.sha256)throw new Error("sha256 mismatch")}else B("b\u1ECF qua ki\u1EC3m tra sha256 (file_system kh\xF4ng c\xF3 sha256)",e.app_id);s();let i=dt(e.app_id,e.version,e.entry,!!e.context_update,(w=e.permissions)!=null?w:[]);return await r.remove(i.dir).catch(()=>{}),await r.mkdir(i.dir),await r.unzip(l,i.dir),lt(e),Nt(e.app_id,[e.version,d==null?void 0:d.version].filter(Boolean)),i}catch(u){throw o?new ee:u}finally{a=null,r.remove(l).catch(()=>{})}},h=((m=se[e.app_id])!=null?m:Promise.resolve()).catch(()=>{}).then(p),M=h.catch(()=>{});return se[e.app_id]=M,M.then(()=>{se[e.app_id]===M&&delete se[e.app_id]}),{promise:h,cancel:()=>{o=!0,a==null||a.cancel()}}},oe={},Ft=__DEV__?0:60*1e3,ut={},ft=(e,t)=>{var r,a;let n=b(e);return n&&Date.now()-((r=ut[t])!=null?r:0)<Ft?Promise.resolve(n):((a=oe[e])!=null||(oe[e]=(async()=>{let o=await fetch(t,{headers:{"Cache-Control":"no-cache"}});if(!o.ok)throw new Error(`manifest ${o.status}`);let l=await o.json(),s=await ke(l,{base_url:t}).promise;return ut[t]=Date.now(),s})().catch(o=>(console.warn("[miniapp] sync failed",e,o==null?void 0:o.message),b(e))).finally(()=>{oe[e]=void 0})),oe[e])};var he=new Map,ht=(e,t)=>(he.set(e,t),()=>{he.get(e)===t&&he.delete(e)}),Bt=(e,t)=>{let n=he.get(e);return n?n(t):!1};import{useRef as Jt,useSyncExternalStore as Vt}from"react";var Ae=e=>{let t=e,n=new Set;return{getState:()=>t,setState:r=>{let a=typeof r=="function"?r(t):r;t={...t,...a},n.forEach(o=>o())},subscribe:r=>(n.add(r),()=>{n.delete(r)})}},W=(e,t,n=Object.is)=>{let r=Jt(null),a=()=>{let o=e.getState(),l=r.current;if(l&&l.state===o&&l.selector===t)return l.value;let s=t(o),p=l&&n(l.value,s)?l.value:s;return r.current={state:o,selector:t,value:p},p};return Vt(e.subscribe,a)};var L=Ae({active_key:null,instances:{}}),At=({app:e,instance_id:t,context:n={},url_params:r={},host_data:a={}},o)=>{var s;let l=(s=S().keep_alive)==null?void 0:s.max_webviews;L.setState(p=>{let g=t!=null?t:e.app_id,h={...p.instances,[g]:{key:g,app:e,context:n,url_params:r,host_data:a,last_used_at:Date.now()}},M=Object.keys(h);return l&&l>0&&M.length>l&&M.filter(m=>m!==g).sort((m,d)=>h[m].last_used_at-h[d].last_used_at).slice(0,M.length-l).forEach(m=>{delete h[m]}),o?{active_key:g,instances:h}:{instances:h}})},Wt=e=>At(e,!0),jt=e=>At(e,!1),ie=()=>L.setState({active_key:null}),me=e=>{L.setState(t=>{if(t.active_key===e||!t.instances[e])return{};let n={...t.instances};return delete n[e],{instances:n}})};var mt="catalog",qt="paused_apps",Ht="removed_apps",Ut=10*1e3,Kt=2,zt=3e3,Yt=()=>{var e;try{return JSON.parse((e=S().storage.getString(mt))!=null?e:"{}")}catch{return{}}},v=Ae({catalog:{},downloads:{},pause_reasons:[]}),Mt=e=>{let t=new Set,n=()=>S().storage.setString(e,JSON.stringify([...t]));return{has:r=>t.has(r),values:()=>[...t],add:r=>t.has(r)?!1:(t.add(r),n(),!0),delete:r=>t.delete(r)?(n(),!0):!1,load:()=>{var r;t.clear();try{let a=JSON.parse((r=S().storage.getString(e))!=null?r:"[]");Array.isArray(a)&&a.forEach(o=>{typeof o=="string"&&t.add(o)})}catch{}}}},$=Mt(qt),K=Mt(Ht);Qe(()=>{$.load(),K.load();let e=Yt(),t={};Object.keys(e).filter(n=>!K.has(n)).forEach(n=>{let r=b(n);r?t[n]={status:"installed",progress:1,version:r.version,has_local:!0}:$.has(n)&&(t[n]={status:"paused",progress:0,version:e[n].version,has_local:!1})}),v.setState({catalog:e,downloads:t})});var De=e=>W(v,t=>e?t.downloads[e]:void 0),Qt=()=>W(v,e=>e.pause_reasons.length>0),J=(...e)=>B("queue",...e),E=[],j={},A=null,Me=new Set,G={},Ie=new Set,X=e=>{Ie.forEach(t=>{try{t(e)}catch(n){console.warn("[miniapp-queue] event listener error",n==null?void 0:n.message)}})},Gt=e=>(Ie.add(e),()=>{Ie.delete(e)}),Xt=()=>v.getState().downloads,C=(e,t)=>{let n=!!b(e),r=v.getState().downloads[e],a=t.status==="downloading"&&n?"updating":t.status,o={...r!=null?r:{status:"queued",progress:0},...t,...a?{status:a}:{},has_local:n};v.setState(l=>({downloads:{...l.downloads,[e]:o}})),(r==null?void 0:r.status)!==o.status||(r==null?void 0:r.version)!==o.version||(r==null?void 0:r.has_local)!==o.has_local?X({type:"status_change",app_id:e,state:o}):r.progress!==o.progress&&X({type:"progress",app_id:e,progress:o.progress,version:o.version})},we=(e,t)=>{var n;(n=G[e])==null||n.forEach(r=>r(t)),delete G[e]},Zt=()=>v.getState().pause_reasons.length>0,U=e=>{var s;if(A)return;let t=e?E.indexOf(e):Zt()?-1:E.findIndex(p=>!$.has(p));if(t<0||t>=E.length)return;let[n]=E.splice(t,1),r=v.getState().catalog[n];if(!r){we(n,b(n)),U();return}let a=Date.now();j[n]=((s=j[n])!=null?s:0)+1,C(n,{status:"downloading",progress:0,version:r.version,error:void 0});let o=0,l=ke(r,{onProgress:p=>{let g=Math.floor(p*100);g!==o&&(o=g,C(n,{progress:g/100,version:r.version}))}});A={app_id:n,handle:l,forced:!!e},J("start",n,r.version,e?"(forced)":""),l.promise.then(p=>{J("installed",n,r.version,`${Date.now()-a}ms`),C(n,{status:"installed",progress:1,version:r.version}),we(n,p)}).catch(p=>{var h;if(p instanceof ee){if(Me.has(n))return;J("paused",n),j[n]-=1,E.unshift(n),C(n,{status:$.has(n)?"paused":"queued",progress:0,version:r.version});return}let g=String((h=p==null?void 0:p.message)!=null?h:p);if(console.warn("[miniapp-queue] failed",n,g),j[n]<Kt){C(n,{status:"queued",progress:0,version:r.version,error:g}),setTimeout(()=>{var M;E.includes(n)||(A==null?void 0:A.app_id)===n||(E.push(n),U((M=G[n])!=null&&M.length?n:void 0))},zt);return}C(n,{status:"failed",progress:0,version:r.version,error:g}),we(n,b(n))}).finally(()=>{A=null;let p=E.find(g=>{var h;return(h=G[g])==null?void 0:h.length});U(p)})},ye=(e,{front:t=!1}={})=>{if((A==null?void 0:A.app_id)===e)return;let n=E.indexOf(e);if(n>=0){if(!t)return;E.splice(n,1)}t?E.unshift(e):E.push(e)},en=async e=>{let{host_id:t,client_token:n}=S(),r=new AbortController,a=setTimeout(()=>r.abort(),Ut);try{let o=`${xe}/api/hosts/${encodeURIComponent(t)}/miniapps?channel=${e}`,l=await fetch(o,{headers:{Authorization:`Bearer ${n}`,"Cache-Control":"no-cache"},signal:r.signal});if(!l.ok)throw new Error(`host list ${e} ${l.status}`);return(await l.json()).apps.map(p=>({...p,channel:e}))}finally{clearTimeout(a)}},ae=null,Le=()=>(ae!=null||(ae=(async()=>{var t;let e=Date.now();try{let n=await Promise.all(S().channels.map(en)),r={};[...n].reverse().flat().forEach(s=>{r[s.app_id]=s});let a=Object.keys(v.getState().catalog).filter(s=>!r[s]);S().storage.setString(mt,JSON.stringify(r)),v.setState({catalog:r}),await Promise.all(a.map(s=>wt(s,{by_user:!1}))),a.forEach(s=>K.delete(s));let o=Object.keys(r).filter(s=>!K.has(s)),l=[];for(let s of o.map(p=>r[p]))await Oe(s)?C(s.app_id,{status:"installed",progress:1,version:s.version}):l.push(s);return l.forEach(s=>{j[s.app_id]=0,C(s.app_id,{status:$.has(s.app_id)?"paused":"queued",progress:0,version:s.version,error:void 0}),ye(s.app_id)}),J("catalog",o.length,"apps, outdated",l.map(s=>s.app_id),"removed",a,`${Date.now()-e}ms`),X({type:"sync_complete",app_ids:o,removed:a}),U(),{ok:!0,app_ids:o,removed:a}}catch(n){let r=String((n==null?void 0:n.name)==="AbortError"?"timeout":(t=n==null?void 0:n.message)!=null?t:n);return console.warn("[miniapp-queue] sync catalog failed",r),X({type:"sync_failed",error:r}),{ok:!1,error:r}}finally{ae=null}})()),ae),wt=async(e,{by_user:t})=>{var a,o,l,s;if(t&&K.add(e),Me.has(e))return;Me.add(e),$.delete(e);let n=E.indexOf(e);n>=0&&E.splice(n,1),(A==null?void 0:A.app_id)===e&&A.handle.cancel();let r=(s=(l=(a=v.getState().downloads[e])==null?void 0:a.version)!=null?l:(o=b(e))==null?void 0:o.version)!=null?s:"";C(e,{status:"uninstalling",progress:0,version:r}),await gt(e),me(e),v.setState(p=>{let g={...p.downloads};return delete g[e],{downloads:g}}),delete j[e],Me.delete(e),we(e,null),J("uninstalled",e,t?"(user)":"(not in list)"),X({type:"uninstalled",app_id:e})},tn=e=>wt(e,{by_user:!0}),nn=e=>{let t=ve(e);return t?(K.delete(e),(A==null?void 0:A.app_id)===e||E.includes(e)||(j[e]=0,C(e,{status:$.has(e)?"paused":"queued",progress:0,version:t.version,error:void 0}),ye(e),U(),J("restore",e)),!0):!1},rn=e=>{if($.has(e))return;if($.add(e),J("pause app",e),(A==null?void 0:A.app_id)===e&&!A.forced){A.handle.cancel();return}let t=v.getState().downloads[e];E.includes(e)&&t&&C(e,{status:"paused",progress:0,version:t.version})},on=e=>{if(!$.delete(e))return;J("resume app",e);let t=v.getState().downloads[e];(t==null?void 0:t.status)==="paused"&&!E.includes(e)&&ve(e)&&(j[e]=0,ye(e)),E.includes(e)&&t&&C(e,{status:"queued",progress:0,version:t.version}),U()},sn=e=>{let{pause_reasons:t}=v.getState();t.includes(e)||(v.setState({pause_reasons:[...t,e]}),J("pause",e),t.length===0&&X({type:"pause_change",paused:!0,reasons:[e]}),A&&!A.forced&&A.handle.cancel())},an=e=>{let{pause_reasons:t}=v.getState();if(!t.includes(e))return;let n=t.filter(r=>r!==e);v.setState({pause_reasons:n}),J("resume",e),n.length===0&&X({type:"pause_change",paused:!1,reasons:n}),U()},pn=()=>Object.values(v.getState().catalog).map(e=>({...e,installed:!!b(e.app_id),removed_by_user:K.has(e.app_id)})),ve=e=>v.getState().catalog[e],$e=async e=>{let t=ve(e);if(!t)return;if($.delete(e),K.delete(e),await Oe(t))return b(e);let n=new Promise(r=>{var a;((a=G[e])!=null?a:G[e]=[]).push(r)});return(A==null?void 0:A.app_id)===e?A.forced=!0:(j[e]=0,ye(e,{front:!0}),A&&!A.forced?A.handle.cancel():U(e)),n};import{Fragment as St,jsx as T,jsxs as ce}from"react/jsx-runtime";var Fe=e=>(e!=null?e:"").replace(/\?[^#]*/,""),yt=0,fn=()=>{let e=new Set;return{emit:t=>e.forEach(n=>n(t)),subscribe:t=>(e.add(t),()=>{e.delete(t)})}},hn=Ve.memo(({instance_key:e,is_active:t,is_front:n,is_dark:r,reload_tick:a,web_at_top:o,splash:l,bridge:s,opaque_background:p,onWebLoadEnd:g})=>{var Ke,ze;let h=N(null),M=N(!1),m=W(L,c=>c.instances[e]),d=m==null?void 0:m.app.app_id,k=m==null?void 0:m.app.manifest_url,w=m==null?void 0:m.context,u=m==null?void 0:m.url_params,[i,x]=Z(()=>d?b(d):null),[q,te]=Z(!1),[bt,je]=Z(0),[xt,ne]=Z(0),[Et,I]=Z(!1),F=N(null),qe=c=>{F.current&&clearTimeout(F.current),F.current=setTimeout(()=>{F.current=null,I(!0)},c)};V(()=>()=>{F.current&&clearTimeout(F.current)},[]),V(()=>{if(!d||!t&&i)return;let c=!0;return te(!1),(async()=>{let f=b(d),R=f?await fe(f):!1;if(!c||(x(R?D=>!D||D.version!==f.version||D.permissions.join(",")!==f.permissions.join(",")?f:D:null),__DEV__&&Date.now()-yt>1e4&&(yt=Date.now(),await Le()),!c))return;let H=await $e(d),z=H!==void 0?H:k?await ft(d,k):b(d);if(c){if(!z){te(!0);return}x(D=>D!=null?D:z)}})(),()=>{c=!1}},[t,d,k,bt]),V(()=>ht(e,c=>h.current?(h.current.postMessage(c),!0):!1),[e]);let Tt=W(v,c=>{let f=d?c.downloads[d]:void 0;return(f==null?void 0:f.status)==="installed"?f.version:void 0});V(()=>{if(t||!d||!i)return;let c=b(d);if(!c||c.version===i.version)return;let f=!0;return fe(c).then(R=>{!f||!R||(B(`webview:${e}`,"\u0111\u1ED5i bundle (\u1EA9n)",i.version,"\u2192",c.version),x(c))}),()=>{f=!1}},[t,d,Tt,i==null?void 0:i.version]),V(()=>{var R;let c=(R=S().keep_alive)==null?void 0:R.idle_close_ms;if(t||!c||c<=0)return;let f=setTimeout(()=>{me(e)},c);return()=>clearTimeout(f)},[t,e]),V(()=>{a>0&&(te(!1),I(!1),ne(c=>c+1),je(c=>c+1))},[a]);let He=N(t);V(()=>{var c;He.current!==t&&(He.current=t,M.current&&((c=h.current)==null||c.injectJavaScript(rt(t?"resumed":"paused"))))},[t]);let le=`${(Ke=i==null?void 0:i.version)!=null?Ke:"none"}:${(ze=i==null?void 0:i.permissions.join(","))!=null?ze:""}:${xt}`,re=Se(()=>JSON.stringify([w!=null?w:{},u!=null?u:{}]),[w,u]),_e=Se(()=>{var c;return pt(u!=null?u:{},(c=i==null?void 0:i.permissions)!=null?c:[])},[re,i==null?void 0:i.permissions]),Rt=Se(()=>it(w!=null?w:{},_e)+nt()+(S().debug?tt():""),[_e]),ue=N(null),Ue=N(null);V(()=>{var f,R,H;if(!i)return;if(Ue.current!==le){Ue.current=le,ue.current=re;return}if(ue.current===re)return;let c=((R=JSON.parse((f=ue.current)!=null?f:"[]")[0])!=null?R:{}).org_id;if(ue.current=re,c===(w==null?void 0:w.org_id)&&M.current){I(!1),qe(1500),(H=h.current)==null||H.injectJavaScript(ot(w!=null?w:{},_e));return}I(!1),ne(z=>z+1)},[re,i,le]);let Pt=Be(async c=>{var R,H,z,D,be;let f=Xe(c.nativeEvent.data);if(!f){if(d&&(s!=null&&s.onWebEvent))try{Promise.resolve(s.onWebEvent(c.nativeEvent.data,{app_id:d,instance_id:e})).catch(y=>{console.warn("[miniapp] onWebEvent l\u1ED7i",d,y)})}catch(y){console.warn("[miniapp] onWebEvent l\u1ED7i",d,y)}return}if(f.method==="log"){let{level:y,text:P}=f;B(`web:${e}`,y!=null?y:"log",P!=null?P:"");return}if(f.method==="pong"){F.current||I(!0);return}if(f.method==="touchAtTop"){o.emit(!!f.at_top);return}if(f.method==="contextApplied"){F.current&&clearTimeout(F.current),F.current=null,I(!0);return}if(f.method==="ready"){M.current=!0,I(!0);let y=(R=L.getState().instances[e])==null?void 0:R.context;y&&((H=h.current)==null||H.injectJavaScript(Re(y)));return}try{let y=await ct(f,{getHostData:()=>{var P,Y;return(Y=(P=L.getState().instances[e])==null?void 0:P.host_data)!=null?Y:{}},getPermissions:()=>{var P,Y;return d?(Y=(P=b(d))==null?void 0:P.permissions)!=null?Y:[]:[]},is_dark:r,close:ie,app_id:d!=null?d:"",instance_id:e,options:s});f.id&&((z=h.current)==null||z.injectJavaScript(Ze(f.id,y)))}catch(y){if(!f.id)return;let P=y==null?void 0:y.code,Y=y instanceof _?y:new _(typeof P=="string"?P:"HOST_ERROR",String((D=y==null?void 0:y.message)!=null?D:y));(be=h.current)==null||be.injectJavaScript(et(f.id,Y))}},[e,r,d,o,s]),Ct=Be(()=>{te(!1),ne(c=>c+1),je(c=>c+1)},[]);return ce(Je,{style:[We.absoluteFill,p&&{backgroundColor:r?"#09090B":"#FFFFFF"},!n&&O.behind],pointerEvents:t?"auto":"none",children:[i?T(gn,{ref:h,source:{uri:i.entry_uri},originWhitelist:["*"],allowingReadAccessToURL:`file://${i.dir}`,allowFileAccess:!0,allowFileAccessFromFileURLs:!0,allowUniversalAccessFromFileURLs:!0,injectedJavaScriptBeforeContentLoaded:Rt,onMessage:Pt,bounces:!1,overScrollMode:"never",onLoadStart:c=>{B(`webview:${e}`,"load start",Fe(c.nativeEvent.url)),M.current=!1,I(!1)},onError:c=>{B(`webview:${e}`,"load error",Fe(c.nativeEvent.url),c.nativeEvent.description),te(!0),I(!1)},onLoadEnd:c=>{let f=c.nativeEvent.url;B(`webview:${e}`,"load end",Fe(f)),d&&(g==null||g({app_id:d,instance_id:e,url:f})),qe(1500)},onContentProcessDidTerminate:()=>{M.current=!1,I(!1),ne(c=>c+1)},onRenderProcessGone:()=>(M.current=!1,I(!1),ne(c=>c+1),!0),style:O.webview},le):null,m&&T(mn,{visible:!i||!Et,interactive:q,children:T(An,{splash:l,app:m.app,is_dark:r,error:q,has_bundle:!!i,retry:Ct})})]})}),An=Ve.memo(({splash:e,app:t,is_dark:n,error:r,has_bundle:a,retry:o})=>{let l=e,s=De(t.app_id),p=r?"error":!a&&(s==null?void 0:s.status)==="downloading"?"downloading":"loading";return T(l,{app:t,is_dark:n,status:p,progress:p==="downloading"?s==null?void 0:s.progress:void 0,retry:o})}),mn=({visible:e,interactive:t,children:n})=>{let r=N(new Ne.Value(e?1:0)).current,[a,o]=Z(e);return V(()=>{if(e){o(!0),r.setValue(1);return}let l=Ne.timing(r,{toValue:0,duration:180,useNativeDriver:!0});return l.start(({finished:s})=>{s&&o(!1)}),()=>l.stop()},[e,r]),a?T(Ne.View,{style:[We.absoluteFill,{opacity:r}],pointerEvents:t?"auto":"none",children:n}):null},_t=({app:e,is_dark:t,status:n,progress:r,retry:a})=>{let o=t?"#FAFAFA":"#18181B";return ce(Je,{style:[O.splash,{backgroundColor:t?"#09090B":"#FFFFFF"}],children:[T(Je,{style:[O.splash_icon,{backgroundColor:t?"#18181B":"#F4F4F5"}],children:e.icon?T(un,{source:{uri:e.icon},style:O.splash_icon_image}):T(pe,{style:O.splash_letter,children:(e.name||"?").slice(0,1).toUpperCase()})}),T(pe,{style:[O.splash_name,{color:o}],children:e.name}),n==="error"?ce(St,{children:[T(pe,{style:O.splash_hint,children:"Kh\xF4ng t\u1EA3i \u0111\u01B0\u1EE3c mini app"}),T(dn,{activeOpacity:.7,style:[O.retry_button,{backgroundColor:t?"#27272A":"#F4F4F5"}],onPress:a,children:T(pe,{style:[O.retry_text,{color:o}],children:"Th\u1EED l\u1EA1i"})})]}):ce(St,{children:[T(cn,{style:O.splash_spinner,color:t?"#A1A1AA":"#71717A"}),n==="downloading"&&ce(pe,{style:O.splash_hint,children:["\u0110ang t\u1EA3i mini app",r?` ${Math.round(r*100)}%`:"\u2026"]})]})]})},vt=(e,t)=>{let n=N(t),r=N(!1);__DEV__&&!r.current&&n.current!==t&&(r.current=!0,console.warn(`[miniapp] MiniAppHost prop "${e}" \u0111\u1ED5i gi\u1EEFa c\xE1c l\u1EA7n render \u2192 m\u1ECDi WebView b\u1ECB mount l\u1EA1i. Khai b\xE1o component b\xEAn ngo\xE0i render.`))},Mn=({container:e,splash:t=_t,is_dark:n=!1,bridge:r,close_on_back:a=!0,opaque_background:o=!0,onWebLoadEnd:l})=>{vt("container",e),vt("splash",t);let s=e,p=W(L,i=>i.active_key),g=N(p);p&&(g.current=p);let h=W(L,i=>Object.keys(i.instances).join("|")),M=W(L,i=>{var x;return i.active_key?(x=i.instances[i.active_key])==null?void 0:x.app.name:void 0}),m=Se(()=>h?h.split("|"):[],[h]),[d,k]=Z({}),w=N(fn()).current;V(()=>{if(!p||!a)return;let i=ln.addEventListener("hardwareBackPress",()=>(ie(),!0));return()=>i.remove()},[p,a]);let u=Be(()=>{let i=L.getState().active_key;i&&k(x=>({...x,[i]:(x[i]||0)+1}))},[]);return m.length?T(s,{visible:!!p,title:M!=null?M:"",is_dark:n,close:ie,reload:u,subscribeWebAtTop:w.subscribe,children:m.map(i=>T(hn,{instance_key:i,is_active:p===i,is_front:(p!=null?p:g.current)===i,is_dark:n,reload_tick:d[i]||0,web_at_top:w,splash:t,bridge:r,opaque_background:o,onWebLoadEnd:l},i))}):null},O=We.create({webview:{flex:1,backgroundColor:"transparent"},behind:{zIndex:-1},splash:{flex:1,alignItems:"center",justifyContent:"center",gap:12},splash_icon:{width:72,height:72,borderRadius:20,alignItems:"center",justifyContent:"center",overflow:"hidden"},splash_icon_image:{width:72,height:72},splash_letter:{fontSize:28,fontWeight:"700",color:"#1D4ED8"},splash_name:{fontSize:16,fontWeight:"600"},splash_hint:{color:"#71717A"},splash_spinner:{marginTop:8},retry_button:{marginTop:4,paddingHorizontal:20,paddingVertical:10,borderRadius:999},retry_text:{fontWeight:"600"}}),wn=Ve.memo(Mn);export{_t as DefaultMiniAppSplash,xe as MINIAPP_PLATFORM_URL,wn as MiniAppHost,_ as MiniAppHostError,ie as closeMiniApp,Ot as configureMiniApp,It as createMmkvStorage,kt as createRnfsFileSystem,$e as ensureMiniApp,b as getLocalMiniApp,pn as getMiniAppCatalog,ve as getMiniAppCatalogEntry,Xt as getMiniAppStatuses,Gt as onMiniAppEvent,Wt as openMiniApp,rn as pauseMiniApp,sn as pauseMiniAppDownloads,jt as preloadMiniApp,nn as restoreMiniApp,on as resumeMiniApp,an as resumeMiniAppDownloads,Bt as sendEventToWeb,Le as syncMiniAppCatalog,tn as uninstallMiniApp,De as useMiniAppDownload,Qt as useMiniAppDownloadsPaused};
package/package.json CHANGED
@@ -1,8 +1,16 @@
1
1
  {
2
2
  "name": "@retion-miniapp/react-native",
3
- "version": "0.5.3",
3
+ "version": "0.7.0",
4
4
  "description": "Host chạy Retion Mini App (bundle web) trong app React Native — chỉ cần react-native-webview",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/vanqui123/retion-miniapp-react-native.git"
9
+ },
10
+ "homepage": "https://github.com/vanqui123/retion-miniapp-react-native/blob/main/docs/MINIAPP_README.md",
11
+ "bugs": {
12
+ "url": "https://github.com/vanqui123/retion-miniapp-react-native/issues"
13
+ },
6
14
  "keywords": [
7
15
  "react-native",
8
16
  "mini-app",
@@ -44,7 +52,21 @@
44
52
  "peerDependencies": {
45
53
  "react": ">=18",
46
54
  "react-native": ">=0.72",
47
- "react-native-webview": ">=13"
55
+ "react-native-webview": ">=13",
56
+ "react-native-fs": ">=2.20",
57
+ "react-native-mmkv": ">=3",
58
+ "react-native-zip-archive": ">=6"
59
+ },
60
+ "peerDependenciesMeta": {
61
+ "react-native-fs": {
62
+ "optional": true
63
+ },
64
+ "react-native-mmkv": {
65
+ "optional": true
66
+ },
67
+ "react-native-zip-archive": {
68
+ "optional": true
69
+ }
48
70
  },
49
71
  "devDependencies": {
50
72
  "@types/react": "^19.2.0",