npm package: @jolibox/ads
Description: This project is for integrating Jolibox ads providers
Latest version: 1.4.16

# @jolibox/ads

## 1. 背景

`@jolibox/ads` 是 Jolibox JSSDK 的核心包之一，主要负责业务层面的广告调用与聚合。它为不同类型的接入方提供了统一的广告接入规范：

- **游戏接入方**：对外暴露 AdSense for Game (AFG) 接口，支持激励视频、插屏广告及 Preroll 等格式。
- **短剧接入方**：对外暴露特定的 AFV (AdSense for Video) 接口，主要用于视频流中的广告插入。

为了最大化广告收益并保证填充率，该包实现了一套高效的广告聚合逻辑，支持从多个广告源 (Provider) 进行瀑布流式的广告加载。

## 2. 目的

- **统一接口**：为前端业务屏蔽底层不同广告供应商（如 Google AdSense, OKSpin, AppsRockets 等）的 API 差异。
- **聚合下发**：通过后端下发的配置，动态决定广告供应商的优先级和调用顺序。
- **高填充率**：通过“瀑布流” (Waterfall) 机制，在一间供应商失败时自动尝试下一间，确保广告展示机会。
- **解耦业务**：将复杂的广告加载、超检测、埋点监控等逻辑封装内部，业务方只需关注简单的 `adBreak` 或 `requestAd` 调用。

## 3. 技术选型

- **TypeScript**: 核心逻辑编写，提供强类型定义。
- **Preact & @preact/signals**: 部分 native 广告 UI 组件的渲染与状态管理。
- **Vite & Esbuild**: 高性能的构建工具链，支持 ESM/CJS/IIFE 多种输出格式。
- **Async/Await Hooks**: 利用 Promise 封装异步回调，简化瀑布流逻辑。

## 4. 架构

项目采用 **Provider 模式** 结合 **Orchestrator (协调者)** 的架构：

- **Providers**: 每个广告平台（如 Google, OKSpin）都被实现为一个独立的 Provider 子类，遵循统一的接口契约 (`IAbstractAFGProvider` / `IAbstractAFVProvider`)。
- **Async Proxies**: `AdBreakAsyncProxy` 和 `AdRequestAsyncProxy` 作为中间件，负责包装 Provider 的回调函数，并将异步回调转化为 Promise 状态，从而支持在循环中按序等待。
- **Orchestrator**: `JoliboxAdsForGame` 和 `JoliboxAdsForVideo` 作为入口类，负责初始化各 Provider，并根据后端下发的序列执行循环调用。

```mermaid
graph TD
    User([业务方调用]) --> Main[JoliboxAdsForGame / Video]
    Main --> FetchConfig[AdsRequest: 获取广告策略]
    FetchConfig --> Loop{瀑布流循环}
    Loop --> Proxy[Async Proxy: 包装回调]
    Proxy --> Provider[Concrete Provider: Google/OKSpin...]
    Provider -- 失败/超时 --> Loop
    Provider -- 成功渲染 --> Done([流程结束])
```

## 5. 目录结构

```bash
src/
├── afg/                # AdSense for Game 相关实现
│   ├── adsense/        # Google AdSense Provider
│   ├── okspin/         # OKSpin Provider
│   ├── native/         # Native 广告逻辑
│   ├── adbreak-async-proxy.ts # AFG 异步代理逻辑
│   └── index.ts        # AFG 入口及瀑布流编排
├── afv/                # AdSense for Video 相关实现
│   ├── ima/            # Google IMA Provider
│   ├── adrequest-async-proxy.ts # AFV 异步代理逻辑
│   └── index.ts        # AFV 入口
├── components/         # 公共组件（如 AdsRequest 请求封装）
├── type/               # 公共类型定义
└── utils/              # 工具函数
```

## 6. 业务分层

- **接入层 (Access Layer)**：`JoliboxAdsForGame` / `JoliboxAdsForVideo` 类，负责面向接入方提供标准的、归一化的 API 接口（如 `adBreak`, `requestAd`）。
- **调度与代理层 (Orchestration & Proxy Layer)**：通过 `AsyncProxy` 将异步回调模式转化为同步 `await` 语义，并实现核心的瀑布流调度逻辑。
- **委派与适配层 (Delegation & Adaptation Layer)**：
  - **二级委派机制**：这是实现的核心。外露接口不直接参与具体的广告加载逻辑，而是将其委派给具体的 `Provider`。
  - 某些复杂的 Provider（如 `GoogleGPT` 或 `Native`）会进行二次委派给专有的 `AdManager`，从而实现**统一外露接口**与**不同广告源具体实现细节**的彻底分离。
- **基础层 (Base Layer)**：`AdsContext` 提供埋点、请求、环境感知的底层支撑。

## 7. 一些实现细节

### Async-Proxy 的实现

为了让分布在不同回调函数（如 `beforeAd`, `adBreakDone` 等）中的逻辑能像同步代码一样在一个循环中执行，我们使用了 `AsyncProxy` 模式：

1. `callAdBreakAndContinue` 返回一个 `Promise`。
2. 内部通过 `wrapAdBreakDone` 等闭包捕获原始回调。
3. 当广告完成、出错或超时时，调用 `resolve` 并返回一个 `continueLoop` 标志。

### 超时处理

在 `AdBreakAsyncProxy` 中内置了 5 秒的保护性超时。如果 Provider 在规定时间内没有触发任何有效回调（如 `beforeAd`），代理层会自动触发 `timeout` 并让瀑布流进入下一个节点。

### Native 广告集成

对于 Native 环境，通过 `NativeProvider` 与客户端通信。在 Web 端，则通过 `AppsRockets` 或 `GoogleGPT` 渲染特定的 UI 组件。

## 8. Provider 重组逻辑 (Reorganization)

在 `init` 和获取广告策略 (`getAFGAdsInfo`/`getAFVAdsInfo`) 阶段，SDK 会对后端下发的 Provider 列表进行重组。其核心目的是**将所有 Native 类型的 Provider 虚拟化为一个统一的 `INTERNAL_NATIVE` 节点**。

### 为什么需要重组？

1. **统一调度语义**：在 JS 层的瀑布流逻辑中，不需要感知 Native 侧具体包含多少个三方 SDK（如 Mintegral, AppLovin 等）。通过重组，JS 侧只需与一个 `NativeProvider` 交互。
2. **职责分离**：JS 侧负责处理 Web 端的多个渠道（Google, OKSpin 等）与 Native 整体之间的优先级；而 Native 侧则利用原生 SDK 的优势，在 `NativeProvider` 内部处理其子级的广告竞价与切换。
3. **简化序列管理**：后端下发的 `seq`（优先级）可以在重组后被重新映射。所有 Native 广告通常被视为一个高优先级的整体块（Block），这保证了在原生 APP 环境下，原生广告始终能被优先调用。

## 9. 广告源实现详情

针对各个广告源的具体实现细节，请参阅以下文档：

- [Google AdSense & BannerAsAFG](docs/adsense.md)
- [OKSpin (AFG & AFV)](docs/okspin.md)
- [AppsRockets (AFG & AFV)](docs/appsrockets.md)
- [Google GPT (AFG & AFV)](docs/googlegpt.md)
- [Google IMA (AFV)](docs/ima.md)
- [Native Provider (Internal)](docs/native.md)

## 10. 开发者深度指南 (AI/Developer Onboarding)

如果你需要在此包上进行二次开发或接入新的广告源，请务必阅读以下规范文档：

- [开发与贡献指南](./docs/CONTRIBUTING.md) - 环境搭建与编码准则。
- [New Provider 接入规范](docs/PROVIDER_SPEC.md) - 定义了接口契约与事件流。
- [跨端通信与原生桥接协议](docs/MESSAGING_PROTOCOL.md) - 定义了 Iframe 与 Native Bridge 的交互细节。
- [后端配置与数据规范](docs/SERVER_CONFIG_SPEC.md) - 详细说明了广告策略接口的字段含义。