@ad-execute-manager/core 2.0.1 → 2.0.3

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/README.md CHANGED
@@ -1,367 +1,367 @@
1
- # @ad-execute-manager/core
2
-
3
- Core functionality for ad execution management including AdExecuteManager, utility functions, and middleware composition.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @ad-execute-manager/core
9
- ```
10
-
11
- ## Features
12
-
13
- - **AdExecuteManager**: A powerful ad execution management class for handling reward-based ads, interstitial ads, and other advertising formats
14
- - **compose**: A middleware composition utility inspired by Koa
15
- - **needRetryAdError**: A utility function for determining if an ad error should be retried
16
-
17
- ## Usage
18
-
19
- ### AdExecuteManager
20
-
21
- ```javascript
22
- import { AdExecuteManager } from '@ad-execute-manager/core';
23
-
24
- const adManager = new AdExecuteManager({
25
- // Configuration options
26
- });
27
-
28
- // Initialize ad
29
- const result = await adManager.init();
30
-
31
- // Show ad
32
- const showResult = await adManager.show();
33
- ```
34
-
35
- ### Middleware Composition
36
-
37
- ```javascript
38
- import { compose } from '@ad-execute-manager/core';
39
-
40
- const middlewares = [
41
- async (ctx, next) => {
42
- console.log('Middleware 1 start');
43
- await next();
44
- console.log('Middleware 1 end');
45
- },
46
- async (ctx, next) => {
47
- console.log('Middleware 2 start');
48
- await next();
49
- console.log('Middleware 2 end');
50
- }
51
- ];
52
-
53
- const composedMiddleware = compose(middlewares);
54
- await composedMiddleware({});
55
- ```
56
-
57
- ### Error Retry Utility
58
-
59
- ```javascript
60
- import { needRetryAdError } from '@ad-execute-manager/core';
61
-
62
- const apiError = {
63
- errMsg: 'ad_show_timeout: normal',
64
- timeout: 5000
65
- };
66
-
67
- const shouldRetry = needRetryAdError({
68
- apiError,
69
- configuredAdTimeout: 5000,
70
- errorRetryStrategy: {
71
- timeout: true,
72
- background: true
73
- }
74
- });
75
-
76
- console.log('Should retry:', shouldRetry);
77
- ```
78
-
79
- ## Examples
80
-
81
- ### 实际应用场景示例
82
-
83
- #### 1. 完整的广告执行流程
84
-
85
- ```javascript
86
- import { AdExecuteManager } from '@ad-execute-manager/core';
87
-
88
- // 创建广告执行管理器实例
89
- const adManager = new AdExecuteManager({
90
- log: true,
91
- enableVisibilityListener: true,
92
- maxRetryCount: 2,
93
- errorRetryStrategy: {
94
- timeout: true,
95
- background: true
96
- }
97
- });
98
-
99
- // 假设我们有一个广告实例类
100
- class MyRewardAd {
101
- constructor() {
102
- this._adTimeoutTime = 5000;
103
- }
104
-
105
- initialize(options) {
106
- console.log('Initializing ad with options:', options);
107
- return this;
108
- }
109
-
110
- async ad(ctx, next) {
111
- const { options, collection, recovered } = ctx;
112
- console.log('Showing ad with options:', options);
113
- console.log('Recovered info:', recovered);
114
-
115
- try {
116
- // 模拟广告加载和显示
117
- await new Promise(resolve => setTimeout(resolve, 1000));
118
-
119
- // 模拟广告成功
120
- if (collection && collection.onSuccess) {
121
- collection.onSuccess();
122
- }
123
-
124
- await next({ success: true });
125
- return { success: true };
126
- } catch (error) {
127
- // 模拟广告失败
128
- if (collection && collection.onFail) {
129
- collection.onFail(error);
130
- }
131
-
132
- await next({ success: false, error });
133
- return { success: false, error };
134
- }
135
- }
136
-
137
- clear() {
138
- console.log('Clearing ad resources');
139
- }
140
-
141
- record(info) {
142
- console.log('Recording ad info:', info);
143
- }
144
- }
145
-
146
- // 创建广告实例
147
- const rewardAd = new MyRewardAd();
148
-
149
- // 添加广告任务
150
- const result = await adManager.addTask(rewardAd, {
151
- options: {
152
- adUnitId: 'your-ad-unit-id',
153
- userId: 'user123'
154
- },
155
- collection: {
156
- onSuccess: () => console.log('Ad success callback'),
157
- onFail: (error) => console.log('Ad fail callback:', error),
158
- onCancel: () => console.log('Ad cancel callback')
159
- }
160
- });
161
-
162
- console.log('Ad execution result:', result);
163
-
164
- // 等待所有任务完成
165
- await adManager.whenAllTasksComplete();
166
- console.log('All tasks completed');
167
- ```
168
-
169
- #### 2. 自定义中间件组合
170
-
171
- ```javascript
172
- import { compose } from '@ad-execute-manager/core';
173
-
174
- // 定义中间件
175
- const middleware1 = async (ctx, next) => {
176
- console.log('Middleware 1 start');
177
- ctx.value1 = 'value1';
178
- await next();
179
- console.log('Middleware 1 end');
180
- };
181
-
182
- const middleware2 = async (ctx, next) => {
183
- console.log('Middleware 2 start');
184
- console.log('Received value1:', ctx.value1);
185
- ctx.value2 = 'value2';
186
- await next();
187
- console.log('Middleware 2 end');
188
- };
189
-
190
- const middleware3 = async (ctx, next) => {
191
- console.log('Middleware 3 start');
192
- console.log('Received value1:', ctx.value1);
193
- console.log('Received value2:', ctx.value2);
194
- ctx.value3 = 'value3';
195
- await next();
196
- console.log('Middleware 3 end');
197
- };
198
-
199
- // 组合中间件
200
- const composedMiddleware = compose([middleware1, middleware2, middleware3]);
201
-
202
- // 执行组合后的中间件
203
- const ctx = { initialValue: 'initial' };
204
- await composedMiddleware(ctx);
205
-
206
- console.log('Final ctx:', ctx);
207
- ```
208
-
209
- #### 3. 错误处理和重试策略
210
-
211
- ```javascript
212
- import { needRetryAdError } from '@ad-execute-manager/core';
213
-
214
- // 模拟不同类型的错误
215
- const timeoutError = {
216
- errMsg: 'ad_show_timeout: normal',
217
- timeout: 5000
218
- };
219
-
220
- const backgroundError = {
221
- errMsg: 'app in background is not support show ad'
222
- };
223
-
224
- const otherError = {
225
- errMsg: 'ad_load_fail: network error'
226
- };
227
-
228
- // 配置重试策略
229
- const retryStrategy = {
230
- timeout: true,
231
- background: true
232
- };
233
-
234
- // 检查各种错误是否需要重试
235
- const shouldRetryTimeout = needRetryAdError({
236
- apiError: timeoutError,
237
- configuredAdTimeout: 5000,
238
- errorRetryStrategy: retryStrategy
239
- });
240
-
241
- const shouldRetryBackground = needRetryAdError({
242
- apiError: backgroundError,
243
- configuredAdTimeout: 5000,
244
- errorRetryStrategy: retryStrategy
245
- });
246
-
247
- const shouldRetryOther = needRetryAdError({
248
- apiError: otherError,
249
- configuredAdTimeout: 5000,
250
- errorRetryStrategy: retryStrategy
251
- });
252
-
253
- console.log('Should retry timeout error:', shouldRetryTimeout);
254
- console.log('Should retry background error:', shouldRetryBackground);
255
- console.log('Should retry other error:', shouldRetryOther);
256
- ```
257
-
258
- ## API
259
-
260
- ### AdExecuteManager
261
-
262
- The main class for managing ad execution with support for initialization, showing, and error handling.
263
-
264
- #### Constructor
265
-
266
- ```javascript
267
- new AdExecuteManager(args)
268
- ```
269
-
270
- - **args** (Object): 构造函数参数
271
- - **options** (Object, optional): 广告执行选项
272
- - **log** (Boolean, optional): 是否打印日志
273
- - **enableVisibilityListener** (Boolean, optional): 是否启用前后台监听
274
- - **maxRetryCount** (Number, optional): 最大重试次数,默认为 1,0 表示不重试
275
- - **errorRetryStrategy** (Object, optional): 错误重试策略
276
- - **timeout** (Boolean, optional): 是否重试超时错误
277
- - **background** (Boolean, optional): 是否重试后台错误
278
-
279
- #### Methods
280
-
281
- - **initialize(_args)**: 初始化 AdExecuteManager 实例
282
- - **_args** (Any): 初始化参数
283
- - 返回: AdExecuteManager 实例
284
-
285
- - **addTask(adInstance, ctx)**: 添加广告任务
286
- - **adInstance** (Object): RewardAdFather 的子类实例
287
- - **ctx** (Object): 广告执行上下文
288
- - **options** (Object): 广告执行选项
289
- - **collection** (Object): 回调集合
290
- - 返回: Promise,广告执行结果的 Promise
291
-
292
- - **clearTasks()**: 清空任务栈并取消所有任务
293
-
294
- - **getTaskCount()**: 获取当前未完成的任务总数
295
- - 返回: Number,未完成的任务数量
296
-
297
- - **isRunning()**: 是否有任务正在运行
298
- - 返回: Boolean
299
-
300
- - **getCurrentTaskId()**: 获取当前执行的任务 ID
301
- - 返回: String|null,当前任务 ID
302
-
303
- - **whenAllTasksComplete()**: 返回一个 Promise,当任务队列中的所有任务都完成时 resolve
304
- - 返回: Promise<void>
305
-
306
- - **enableVisibilityListener()**: 启用前后台监听
307
-
308
- - **disableVisibilityListener()**: 禁用前后台监听
309
-
310
- - **isVisibilityListenerEnabled()**: 获取前后台监听器状态
311
- - 返回: Boolean,是否启用
312
-
313
- - **destroyVisibilityListener()**: 销毁前后台监听器
314
-
315
- - **static getInstance(args)**: 获取单例实例
316
- - **args** (Object, optional): 构造函数参数
317
- - 返回: AdExecuteManager 实例
318
-
319
- - **static build(args)**: 获取单例实例
320
- - **args** (Object, optional): 构造函数参数
321
- - 返回: AdExecuteManager 实例
322
-
323
- - **static new(args)**: 创建新实例
324
- - **args** (Object, optional): 构造函数参数
325
- - 返回: AdExecuteManager 实例
326
-
327
- - **static getSafeInstance()**: 获取单例实例,如果不存在则返回 null
328
- - 返回: AdExecuteManager|null
329
-
330
- ### compose
331
-
332
- ```typescript
333
- function compose(middlewares: Array<(ctx: any, next: () => Promise<void>) => Promise<void>>): (ctx: any) => Promise<void>
334
- ```
335
-
336
- - **middlewares** (Array<Function>): KOA 中间件数组,每个中间件函数接收 ctx 和 next 参数
337
- - 返回: Function,返回一个组合后的中间件函数,接收 ctx 参数并按顺序执行所有中间件
338
-
339
- ### needRetryAdError
340
-
341
- ```typescript
342
- function needRetryAdError({
343
- apiError,
344
- configuredAdTimeout,
345
- errorRetryStrategy
346
- }: {
347
- apiError: { errMsg?: string; timeout?: number };
348
- configuredAdTimeout: number;
349
- errorRetryStrategy?: {
350
- timeout?: boolean;
351
- background?: boolean;
352
- };
353
- }): boolean
354
- ```
355
-
356
- - **apiError** (Object): 广告错误信息
357
- - **errMsg** (String, optional): 错误信息
358
- - **timeout** (Number, optional): 超时时间
359
- - **configuredAdTimeout** (Number): 配置的广告超时时间
360
- - **errorRetryStrategy** (Object, optional): 错误重试策略
361
- - **timeout** (Boolean, optional): 是否重试超时错误
362
- - **background** (Boolean, optional): 是否重试后台错误
363
- - 返回: Boolean,是否需要重试
364
-
365
- ## License
366
-
367
- MIT
1
+ # @ad-execute-manager/core
2
+
3
+ Core functionality for ad execution management including AdExecuteManager, utility functions, and middleware composition.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @ad-execute-manager/core
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **AdExecuteManager**: A powerful ad execution management class for handling reward-based ads, interstitial ads, and other advertising formats
14
+ - **compose**: A middleware composition utility inspired by Koa
15
+ - **needRetryAdError**: A utility function for determining if an ad error should be retried
16
+
17
+ ## Usage
18
+
19
+ ### AdExecuteManager
20
+
21
+ ```javascript
22
+ import { AdExecuteManager } from '@ad-execute-manager/core';
23
+
24
+ const adManager = new AdExecuteManager({
25
+ // Configuration options
26
+ });
27
+
28
+ // Initialize ad
29
+ const result = await adManager.init();
30
+
31
+ // Show ad
32
+ const showResult = await adManager.show();
33
+ ```
34
+
35
+ ### Middleware Composition
36
+
37
+ ```javascript
38
+ import { compose } from '@ad-execute-manager/core';
39
+
40
+ const middlewares = [
41
+ async (ctx, next) => {
42
+ console.log('Middleware 1 start');
43
+ await next();
44
+ console.log('Middleware 1 end');
45
+ },
46
+ async (ctx, next) => {
47
+ console.log('Middleware 2 start');
48
+ await next();
49
+ console.log('Middleware 2 end');
50
+ }
51
+ ];
52
+
53
+ const composedMiddleware = compose(middlewares);
54
+ await composedMiddleware({});
55
+ ```
56
+
57
+ ### Error Retry Utility
58
+
59
+ ```javascript
60
+ import { needRetryAdError } from '@ad-execute-manager/core';
61
+
62
+ const apiError = {
63
+ errMsg: 'ad_show_timeout: normal',
64
+ timeout: 5000
65
+ };
66
+
67
+ const shouldRetry = needRetryAdError({
68
+ apiError,
69
+ configuredAdTimeout: 5000,
70
+ errorRetryStrategy: {
71
+ timeout: true,
72
+ background: true
73
+ }
74
+ });
75
+
76
+ console.log('Should retry:', shouldRetry);
77
+ ```
78
+
79
+ ## Examples
80
+
81
+ ### 实际应用场景示例
82
+
83
+ #### 1. 完整的广告执行流程
84
+
85
+ ```javascript
86
+ import { AdExecuteManager } from '@ad-execute-manager/core';
87
+
88
+ // 创建广告执行管理器实例
89
+ const adManager = new AdExecuteManager({
90
+ log: true,
91
+ enableVisibilityListener: true,
92
+ maxRetryCount: 2,
93
+ errorRetryStrategy: {
94
+ timeout: true,
95
+ background: true
96
+ }
97
+ });
98
+
99
+ // 假设我们有一个广告实例类
100
+ class MyRewardAd {
101
+ constructor() {
102
+ this._adTimeoutTime = 5000;
103
+ }
104
+
105
+ initialize(options) {
106
+ console.log('Initializing ad with options:', options);
107
+ return this;
108
+ }
109
+
110
+ async ad(ctx, next) {
111
+ const { options, collection, recovered } = ctx;
112
+ console.log('Showing ad with options:', options);
113
+ console.log('Recovered info:', recovered);
114
+
115
+ try {
116
+ // 模拟广告加载和显示
117
+ await new Promise(resolve => setTimeout(resolve, 1000));
118
+
119
+ // 模拟广告成功
120
+ if (collection && collection.onSuccess) {
121
+ collection.onSuccess();
122
+ }
123
+
124
+ await next({ success: true });
125
+ return { success: true };
126
+ } catch (error) {
127
+ // 模拟广告失败
128
+ if (collection && collection.onFail) {
129
+ collection.onFail(error);
130
+ }
131
+
132
+ await next({ success: false, error });
133
+ return { success: false, error };
134
+ }
135
+ }
136
+
137
+ clear() {
138
+ console.log('Clearing ad resources');
139
+ }
140
+
141
+ record(info) {
142
+ console.log('Recording ad info:', info);
143
+ }
144
+ }
145
+
146
+ // 创建广告实例
147
+ const rewardAd = new MyRewardAd();
148
+
149
+ // 添加广告任务
150
+ const result = await adManager.addTask(rewardAd, {
151
+ options: {
152
+ adUnitId: 'your-ad-unit-id',
153
+ userId: 'user123'
154
+ },
155
+ collection: {
156
+ onSuccess: () => console.log('Ad success callback'),
157
+ onFail: (error) => console.log('Ad fail callback:', error),
158
+ onCancel: () => console.log('Ad cancel callback')
159
+ }
160
+ });
161
+
162
+ console.log('Ad execution result:', result);
163
+
164
+ // 等待所有任务完成
165
+ await adManager.whenAllTasksComplete();
166
+ console.log('All tasks completed');
167
+ ```
168
+
169
+ #### 2. 自定义中间件组合
170
+
171
+ ```javascript
172
+ import { compose } from '@ad-execute-manager/core';
173
+
174
+ // 定义中间件
175
+ const middleware1 = async (ctx, next) => {
176
+ console.log('Middleware 1 start');
177
+ ctx.value1 = 'value1';
178
+ await next();
179
+ console.log('Middleware 1 end');
180
+ };
181
+
182
+ const middleware2 = async (ctx, next) => {
183
+ console.log('Middleware 2 start');
184
+ console.log('Received value1:', ctx.value1);
185
+ ctx.value2 = 'value2';
186
+ await next();
187
+ console.log('Middleware 2 end');
188
+ };
189
+
190
+ const middleware3 = async (ctx, next) => {
191
+ console.log('Middleware 3 start');
192
+ console.log('Received value1:', ctx.value1);
193
+ console.log('Received value2:', ctx.value2);
194
+ ctx.value3 = 'value3';
195
+ await next();
196
+ console.log('Middleware 3 end');
197
+ };
198
+
199
+ // 组合中间件
200
+ const composedMiddleware = compose([middleware1, middleware2, middleware3]);
201
+
202
+ // 执行组合后的中间件
203
+ const ctx = { initialValue: 'initial' };
204
+ await composedMiddleware(ctx);
205
+
206
+ console.log('Final ctx:', ctx);
207
+ ```
208
+
209
+ #### 3. 错误处理和重试策略
210
+
211
+ ```javascript
212
+ import { needRetryAdError } from '@ad-execute-manager/core';
213
+
214
+ // 模拟不同类型的错误
215
+ const timeoutError = {
216
+ errMsg: 'ad_show_timeout: normal',
217
+ timeout: 5000
218
+ };
219
+
220
+ const backgroundError = {
221
+ errMsg: 'app in background is not support show ad'
222
+ };
223
+
224
+ const otherError = {
225
+ errMsg: 'ad_load_fail: network error'
226
+ };
227
+
228
+ // 配置重试策略
229
+ const retryStrategy = {
230
+ timeout: true,
231
+ background: true
232
+ };
233
+
234
+ // 检查各种错误是否需要重试
235
+ const shouldRetryTimeout = needRetryAdError({
236
+ apiError: timeoutError,
237
+ configuredAdTimeout: 5000,
238
+ errorRetryStrategy: retryStrategy
239
+ });
240
+
241
+ const shouldRetryBackground = needRetryAdError({
242
+ apiError: backgroundError,
243
+ configuredAdTimeout: 5000,
244
+ errorRetryStrategy: retryStrategy
245
+ });
246
+
247
+ const shouldRetryOther = needRetryAdError({
248
+ apiError: otherError,
249
+ configuredAdTimeout: 5000,
250
+ errorRetryStrategy: retryStrategy
251
+ });
252
+
253
+ console.log('Should retry timeout error:', shouldRetryTimeout);
254
+ console.log('Should retry background error:', shouldRetryBackground);
255
+ console.log('Should retry other error:', shouldRetryOther);
256
+ ```
257
+
258
+ ## API
259
+
260
+ ### AdExecuteManager
261
+
262
+ The main class for managing ad execution with support for initialization, showing, and error handling.
263
+
264
+ #### Constructor
265
+
266
+ ```javascript
267
+ new AdExecuteManager(args)
268
+ ```
269
+
270
+ - **args** (Object): 构造函数参数
271
+ - **options** (Object, optional): 广告执行选项
272
+ - **log** (Boolean, optional): 是否打印日志
273
+ - **enableVisibilityListener** (Boolean, optional): 是否启用前后台监听
274
+ - **maxRetryCount** (Number, optional): 最大重试次数,默认为 1,0 表示不重试
275
+ - **errorRetryStrategy** (Object, optional): 错误重试策略
276
+ - **timeout** (Boolean, optional): 是否重试超时错误
277
+ - **background** (Boolean, optional): 是否重试后台错误
278
+
279
+ #### Methods
280
+
281
+ - **initialize(_args)**: 初始化 AdExecuteManager 实例
282
+ - **_args** (Any): 初始化参数
283
+ - 返回: AdExecuteManager 实例
284
+
285
+ - **addTask(adInstance, ctx)**: 添加广告任务
286
+ - **adInstance** (Object): RewardAdFather 的子类实例
287
+ - **ctx** (Object): 广告执行上下文
288
+ - **options** (Object): 广告执行选项
289
+ - **collection** (Object): 回调集合
290
+ - 返回: Promise,广告执行结果的 Promise
291
+
292
+ - **clearTasks()**: 清空任务栈并取消所有任务
293
+
294
+ - **getTaskCount()**: 获取当前未完成的任务总数
295
+ - 返回: Number,未完成的任务数量
296
+
297
+ - **isRunning()**: 是否有任务正在运行
298
+ - 返回: Boolean
299
+
300
+ - **getCurrentTaskId()**: 获取当前执行的任务 ID
301
+ - 返回: String|null,当前任务 ID
302
+
303
+ - **whenAllTasksComplete()**: 返回一个 Promise,当任务队列中的所有任务都完成时 resolve
304
+ - 返回: Promise<void>
305
+
306
+ - **enableVisibilityListener()**: 启用前后台监听
307
+
308
+ - **disableVisibilityListener()**: 禁用前后台监听
309
+
310
+ - **isVisibilityListenerEnabled()**: 获取前后台监听器状态
311
+ - 返回: Boolean,是否启用
312
+
313
+ - **destroyVisibilityListener()**: 销毁前后台监听器
314
+
315
+ - **static getInstance(args)**: 获取单例实例
316
+ - **args** (Object, optional): 构造函数参数
317
+ - 返回: AdExecuteManager 实例
318
+
319
+ - **static build(args)**: 获取单例实例
320
+ - **args** (Object, optional): 构造函数参数
321
+ - 返回: AdExecuteManager 实例
322
+
323
+ - **static new(args)**: 创建新实例
324
+ - **args** (Object, optional): 构造函数参数
325
+ - 返回: AdExecuteManager 实例
326
+
327
+ - **static getSafeInstance()**: 获取单例实例,如果不存在则返回 null
328
+ - 返回: AdExecuteManager|null
329
+
330
+ ### compose
331
+
332
+ ```typescript
333
+ function compose(middlewares: Array<(ctx: any, next: () => Promise<void>) => Promise<void>>): (ctx: any) => Promise<void>
334
+ ```
335
+
336
+ - **middlewares** (Array<Function>): KOA 中间件数组,每个中间件函数接收 ctx 和 next 参数
337
+ - 返回: Function,返回一个组合后的中间件函数,接收 ctx 参数并按顺序执行所有中间件
338
+
339
+ ### needRetryAdError
340
+
341
+ ```typescript
342
+ function needRetryAdError({
343
+ apiError,
344
+ configuredAdTimeout,
345
+ errorRetryStrategy
346
+ }: {
347
+ apiError: { errMsg?: string; timeout?: number };
348
+ configuredAdTimeout: number;
349
+ errorRetryStrategy?: {
350
+ timeout?: boolean;
351
+ background?: boolean;
352
+ };
353
+ }): boolean
354
+ ```
355
+
356
+ - **apiError** (Object): 广告错误信息
357
+ - **errMsg** (String, optional): 错误信息
358
+ - **timeout** (Number, optional): 超时时间
359
+ - **configuredAdTimeout** (Number): 配置的广告超时时间
360
+ - **errorRetryStrategy** (Object, optional): 错误重试策略
361
+ - **timeout** (Boolean, optional): 是否重试超时错误
362
+ - **background** (Boolean, optional): 是否重试后台错误
363
+ - 返回: Boolean,是否需要重试
364
+
365
+ ## License
366
+
367
+ MIT
@@ -90,6 +90,20 @@ export type IConstructArgs = {
90
90
  */
91
91
  errorRetryStrategy?: ErrorRetryStrategy;
92
92
  };
93
+ export type ITaskResult = {
94
+ /**
95
+ * 广告任务的唯一标识符
96
+ */
97
+ id: string;
98
+ /**
99
+ * 广告错误信息
100
+ */
101
+ apiError?: import("./typings/ad.js").IApiError;
102
+ /**
103
+ * 广告任务后台恢复前台时预估重试次数的原因
104
+ */
105
+ recovered?: import("./typings/ad.js").RecoveredInfo;
106
+ };
93
107
  declare class AdExecuteManager {
94
108
  /**
95
109
  * 单例实例
@@ -212,12 +226,14 @@ declare class AdExecuteManager {
212
226
  * @param {Object} ctx 广告执行上下文
213
227
  * @param {IRewordAdConfig} ctx.options 广告执行选项
214
228
  * @param {CallbackCollection} ctx.collection 回调集合
215
- * @returns {Promise} 广告执行结果的Promise
229
+ * @returns {Promise.<ITaskResult & {[key: string]: any}> | Undefined>} 广告执行结果的Promise
216
230
  */
217
231
  addTask(adInstance: IAdInstance, ctx: {
218
232
  options: IRewordAdConfig;
219
233
  collection: CallbackCollection;
220
- }): Promise<any>;
234
+ }): Promise<ITaskResult & {
235
+ [key: string]: any;
236
+ }> | undefined;
221
237
  /**
222
238
  * 组合所有任务
223
239
  * @private
@@ -249,4 +265,4 @@ declare class AdExecuteManager {
249
265
  */
250
266
  whenAllTasksComplete(): Promise<void>;
251
267
  }
252
- import { Logger } from '@ad-execute-manager/helper';
268
+ import { Logger } from '@ad-execute-manager/logger';
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,t)=>{for(var r in t)__webpack_require__.o(t,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{AdExecuteManager:()=>src_AdExecuteManager});const helper_namespaceObject=require("@ad-execute-manager/helper");function isTimeoutError(e,t){return(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&e.errMsg.startsWith("ad_show_timeout: normal")&&(null==e?void 0:e.timeout)==t}function isBackgroundError(e){return(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&(e.errMsg.startsWith("app in background is not support show ad")||e.errMsg.startsWith("other controller is presented"))}function needRetryAdError({apiError:e,configuredAdTimeout:t,errorRetryStrategy:r}){return!!((null==r?void 0:r.timeout)&&isTimeoutError(e,t)||(null==r?void 0:r.background)&&isBackgroundError(e))}const compose=e=>e.map(e=>(t,r)=>async i=>await e(Object.assign({},t,i),r)).reduce((e,t)=>(r,i)=>e(r,t(r,i))),src_compose=compose;class AdExecuteManager{static _instance=null;_taskStack=[];_currentBatchTasks=[];_isRunning=!1;_currentTask=null;_isForeground=!0;_appShowListener=null;_appHideListener=null;_enableVisibilityListener=!1;_maxRetryCount=1;_retryQueue=[];_errorRetryStrategy={timeout:!0,background:!0};constructor(e){this.logger=new helper_namespaceObject.Logger({prefix:"AdExecuteManager",enabled:!!(null==e?void 0:e.log)}),(null==e?void 0:e.errorRetryStrategy)&&(this._errorRetryStrategy=Object.assign({},this._errorRetryStrategy,null==e?void 0:e.errorRetryStrategy)),this._enableVisibilityListener=null==e?void 0:e.enableVisibilityListener,this._maxRetryCount=(null==e?void 0:e.maxRetryCount)??1,this._enableVisibilityListener&&this._initVisibilityListener()}initialize(e){return this}static getInstance(e){return AdExecuteManager._instance||(AdExecuteManager._instance=new AdExecuteManager(e)),AdExecuteManager._instance}static build(e){return AdExecuteManager._instance||(AdExecuteManager._instance=new AdExecuteManager(e)),AdExecuteManager._instance}static new(e){return new AdExecuteManager(e)}static getSafeInstance(){return AdExecuteManager._instance?AdExecuteManager._instance:(this.logger.error("AdExecuteManager实例不存在"),null)}_initVisibilityListener(){!("u"<typeof tt)&&tt.onAppShow&&tt.onAppHide?(this._appShowListener=()=>{this._isForeground=!0,this._handleAppShow()},this._appHideListener=()=>{this._isForeground=!1,this._handleAppHide()},tt.onAppShow(this._appShowListener),tt.onAppHide(this._appHideListener),this.logger.info("前后台监听器已初始化")):this.logger.warn("tt API不可用,无法监听前后台状态")}_handleAppHide(){if(this._isRunning&&this._currentBatchTasks.length>0){let e=this._currentBatchTasks.filter(e=>{var t;return e.id!==(null==(t=this._currentTask)?void 0:t.id)&&!e._isResolved&&!e._isRejected});e.length>0&&(this.logger.info(`将 ${e.length} 个未执行的任务放回任务栈,任务ID: ${e.map(e=>e.id).join(",")}`),this._taskStack=[...e,...this._taskStack],this._currentBatchTasks=this._currentBatchTasks.filter(t=>!e.some(e=>e.id===t.id)))}}_handleAppShow(){this._retryQueue.length>0&&(this.logger.info(`应用进入前台:优先执行重试队列,任务数: ${this._retryQueue.length}, 任务ID: ${this._retryQueue.map(e=>e.id).join(",")}`),this._taskStack=[...this._retryQueue,...this._taskStack],this._retryQueue=[]),this._taskStack.length>0&&!this._isRunning&&(this.logger.info(`应用进入前台:恢复待执行任务数: ${this._taskStack.length}, 任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._compose())}destroyVisibilityListener(){this._appShowListener&&"u">typeof tt&&tt.offAppShow&&(tt.offAppShow(this._appShowListener),this._appShowListener=null),this._appHideListener&&"u">typeof tt&&tt.offAppHide&&(tt.offAppHide(this._appHideListener),this._appHideListener=null),this.logger.info("前后台监听器已销毁")}enableVisibilityListener(){this._enableVisibilityListener||(this._enableVisibilityListener=!0,this._initVisibilityListener()),this.logger.info("前后台监听器已启用")}disableVisibilityListener(){this._enableVisibilityListener&&(this._enableVisibilityListener=!1,this.destroyVisibilityListener()),this.logger.info("前后台监听器已禁用")}isVisibilityListenerEnabled(){return this._enableVisibilityListener}addTask(e,t){return e&&"function"==typeof e.ad?new Promise((r,i)=>{let s={adInstance:e,options:t.options??{},callbackCollection:t.collection??{},resolve:r,reject:i,id:`ad_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,_isResolved:!1,_isRejected:!1,_retryCount:0,_retryMsg:"ok"};this._taskStack.push(s),this._isRunning||this._compose()}):(this.logger.error("无效的广告实例 请正确实现.ad方法"),Promise.reject(Error("无效的广告实例")))}_compose(){if(0===this._taskStack.length){this._isRunning=!1,this._currentTask=null;return}if(!this._isForeground){this.logger.info(`应用处于后台,暂停任务执行,任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._isRunning=!1;return}this._isRunning=!0;let e=[...this._taskStack];this._taskStack=[],this._currentBatchTasks=e;let t=e.map(e=>async(t,r)=>{let{adInstance:i,options:s,callbackCollection:n,resolve:a,id:o,_retryCount:c,_retryMsg:l}=e,_={count:c,retry:c>0,message:l};if(e._isResolved||e._isRejected)return void await r(t);this._currentTask=e;try{let c=async e=>{await r(Object.assign({},t,e))},l=await i.initialize(s).ad({options:s,collection:n,recovered:_},c),h=Object.assign({id:o,recovered:_},l);if(this.logger.info(`任务执行成功,成功信息:${JSON.stringify(h)}`),needRetryAdError({apiError:null==h?void 0:h.apiError,configuredAdTimeout:i._adTimeoutTime,errorRetryStrategy:this._errorRetryStrategy})&&!this._isForeground&&e._retryCount<this._maxRetryCount){var u;e._retryCount++,e._retryMsg=(null==h||null==(u=h.apiError)?void 0:u.errMsg)||"unknown";let t=`任务 ${o} 在后台失败,加入重试队列 (即将第 ${e._retryCount} 次重试, 最大重试次数 ${this._maxRetryCount}, 重试原因: ${e._retryMsg})`;this.logger.warn(t),h.recovered.retry=!0,h.recovered.count=e._retryCount,h.recovered.message=e._retryMsg,e._isResolved=!1,e._isRejected=!1,this._retryQueue.push(e)}else e._isResolved=!0;a(h),null==i||i.record(h)}catch(n){let s=Object.assign({id:o,apiError:n,recovered:_});this.logger.error(`任务执行失败, 继续下一个任务,错误信息:${JSON.stringify(s)}`),e._isRejected=!0;try{null==i||i.clear()}catch(e){this.logger.error("clear error: ",JSON.stringify(Object.assign({id:o,apiError:e})))}a(s),null==i||i.record(s),await r(t)}}),r={roundTasks:t.length};compose(t)(r,async e=>{this.logger.info("本轮活动队列已经清空",e),this._taskStack.length>0?Promise.resolve().then(()=>{this._compose()}):(this._isRunning=!1,this._currentTask=null,this._currentBatchTasks=[])})()}clearTasks(){if(this._currentTask){if(this._currentTask._isResolved||this._currentTask._isRejected){this._currentTask=null;return}try{this._currentTask.callbackCollection&&this._currentTask.callbackCollection.onCancel&&this._currentTask.callbackCollection.onCancel(),this._currentTask._isResolved=!0,this._currentTask.resolve()}catch(e){this.logger.error("clear current task error: ",e)}this._currentTask=null}this._currentBatchTasks.length>0&&(this._currentBatchTasks.forEach(e=>{if(e!==this._currentTask&&!e._isResolved&&!e._isRejected)try{e.callbackCollection&&e.callbackCollection.onCancel&&e.callbackCollection.onCancel(),e._isResolved=!0,e.resolve()}catch(e){this.logger.error("clear current batch task error: ",e)}}),this._currentBatchTasks=[]),this._taskStack.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.onCancel))try{e.callbackCollection.onCancel()}catch(e){this.logger.error("clear task error: ",e)}}),this._retryQueue.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.onCancel))try{e.callbackCollection.onCancel()}catch(e){this.logger.error("clear retry task error: ",e)}}),this._taskStack=[],this._retryQueue=[],this._isRunning=!1}getTaskCount(){return this._taskStack.filter(e=>!e._isResolved&&!e._isRejected).length+this._currentBatchTasks.filter(e=>e!==this._currentTask&&!e._isResolved&&!e._isRejected).length+(!this._currentTask||this._currentTask._isResolved||this._currentTask._isRejected?0:1)+this._retryQueue.filter(e=>!e._isResolved&&!e._isRejected).length}isRunning(){return this._isRunning}getCurrentTaskId(){var e;return(null==(e=this._currentTask)?void 0:e.id)||null}whenAllTasksComplete(){return new Promise(e=>{let t=null,r=()=>{let i=0===this._taskStack.length,s=!this._isRunning,n=null===this._currentTask,a=0===this._currentBatchTasks.length||this._currentBatchTasks.every(e=>e._isResolved||e._isRejected),o=0===this._retryQueue.length;i&&s&&n&&a&&o?(t&&clearTimeout(t),e()):t=setTimeout(r,500)};r()})}}const src_AdExecuteManager=AdExecuteManager;for(var __rspack_i in exports.AdExecuteManager=__webpack_exports__.AdExecuteManager,__webpack_exports__)-1===["AdExecuteManager"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
1
+ "use strict";const __rslib_import_meta_url__="u"<typeof document?new(require("url".replace("",""))).URL("file:"+__filename).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href;var __webpack_require__={};__webpack_require__.d=(e,t)=>{for(var r in t)__webpack_require__.o(t,r)&&!__webpack_require__.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"u">typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__={};__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,{AdExecuteManager:()=>src_AdExecuteManager});const logger_namespaceObject=require("@ad-execute-manager/logger");function isTimeoutError(e,t){return(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&e.errMsg.startsWith("ad_show_timeout: normal")&&(null==e?void 0:e.timeout)==t}function isBackgroundError(e){return(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&(e.errMsg.startsWith("app in background is not support show ad")||e.errMsg.startsWith("other controller is presented"))}function needRetryAdError({apiError:e,configuredAdTimeout:t,errorRetryStrategy:r}){return!!((null==r?void 0:r.timeout)&&isTimeoutError(e,t)||(null==r?void 0:r.background)&&isBackgroundError(e))}const compose=e=>e.map(e=>(t,r)=>async i=>await e(Object.assign({},t,i),r)).reduce((e,t)=>(r,i)=>e(r,t(r,i))),src_compose=compose;class AdExecuteManager{static _instance=null;_taskStack=[];_currentBatchTasks=[];_isRunning=!1;_currentTask=null;_isForeground=!0;_appShowListener=null;_appHideListener=null;_enableVisibilityListener=!1;_maxRetryCount=1;_retryQueue=[];_errorRetryStrategy={timeout:!0,background:!0};constructor(e){this.logger=new logger_namespaceObject.Logger({prefix:"AdExecuteManager",enabled:!!(null==e?void 0:e.log)}),(null==e?void 0:e.errorRetryStrategy)&&(this._errorRetryStrategy=Object.assign({},this._errorRetryStrategy,null==e?void 0:e.errorRetryStrategy)),this._enableVisibilityListener=null==e?void 0:e.enableVisibilityListener,this._maxRetryCount=(null==e?void 0:e.maxRetryCount)??1,this._enableVisibilityListener&&this._initVisibilityListener()}initialize(e){return this}static getInstance(e){return AdExecuteManager._instance||(AdExecuteManager._instance=new AdExecuteManager(e)),AdExecuteManager._instance}static build(e){return AdExecuteManager._instance||(AdExecuteManager._instance=new AdExecuteManager(e)),AdExecuteManager._instance}static new(e){return new AdExecuteManager(e)}static getSafeInstance(){return AdExecuteManager._instance?AdExecuteManager._instance:(this.logger.error("AdExecuteManager实例不存在"),null)}_initVisibilityListener(){!("u"<typeof tt)&&tt.onAppShow&&tt.onAppHide?(this._appShowListener=()=>{this._isForeground=!0,this._handleAppShow()},this._appHideListener=()=>{this._isForeground=!1,this._handleAppHide()},tt.onAppShow(this._appShowListener),tt.onAppHide(this._appHideListener),this.logger.info("前后台监听器已初始化")):this.logger.warn("tt API不可用,无法监听前后台状态")}_handleAppHide(){if(this._isRunning&&this._currentBatchTasks.length>0){let e=this._currentBatchTasks.filter(e=>{var t;return e.id!==(null==(t=this._currentTask)?void 0:t.id)&&!e._isResolved&&!e._isRejected});e.length>0&&(this.logger.info(`将 ${e.length} 个未执行的任务放回任务栈,任务ID: ${e.map(e=>e.id).join(",")}`),this._taskStack=[...e,...this._taskStack],this._currentBatchTasks=this._currentBatchTasks.filter(t=>!e.some(e=>e.id===t.id)))}}_handleAppShow(){this._retryQueue.length>0&&(this.logger.info(`应用进入前台:优先执行重试队列,任务数: ${this._retryQueue.length}, 任务ID: ${this._retryQueue.map(e=>e.id).join(",")}`),this._taskStack=[...this._retryQueue,...this._taskStack],this._retryQueue=[]),this._taskStack.length>0&&!this._isRunning&&(this.logger.info(`应用进入前台:恢复待执行任务数: ${this._taskStack.length}, 任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._compose())}destroyVisibilityListener(){this._appShowListener&&"u">typeof tt&&tt.offAppShow&&(tt.offAppShow(this._appShowListener),this._appShowListener=null),this._appHideListener&&"u">typeof tt&&tt.offAppHide&&(tt.offAppHide(this._appHideListener),this._appHideListener=null),this.logger.info("前后台监听器已销毁")}enableVisibilityListener(){this._enableVisibilityListener||(this._enableVisibilityListener=!0,this._initVisibilityListener()),this.logger.info("前后台监听器已启用")}disableVisibilityListener(){this._enableVisibilityListener&&(this._enableVisibilityListener=!1,this.destroyVisibilityListener()),this.logger.info("前后台监听器已禁用")}isVisibilityListenerEnabled(){return this._enableVisibilityListener}addTask(e,t){return e&&"function"==typeof e.ad?new Promise((r,i)=>{let s={adInstance:e,options:t.options??{},callbackCollection:t.collection??{},resolve:r,reject:i,id:`ad_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,_isResolved:!1,_isRejected:!1,_retryCount:0,_retryMsg:"ok"};this._taskStack.push(s),this._isRunning||this._compose()}):(this.logger.error("无效的广告实例 请正确实现.ad方法"),Promise.reject(Error("无效的广告实例")))}_compose(){if(0===this._taskStack.length){this._isRunning=!1,this._currentTask=null;return}if(!this._isForeground){this.logger.info(`应用处于后台,暂停任务执行,任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._isRunning=!1;return}this._isRunning=!0;let e=[...this._taskStack];this._taskStack=[],this._currentBatchTasks=e;let t=e.map(e=>async(t,r)=>{let{adInstance:i,options:s,callbackCollection:n,resolve:a,id:o,_retryCount:c,_retryMsg:l}=e,_={count:c,retry:c>0,message:l};if(e._isResolved||e._isRejected)return void await r(t);this._currentTask=e;try{let c=async e=>{await r(Object.assign({},t,e))},l=await i.initialize(s).ad({options:s,collection:n,recovered:_},c),h=Object.assign({id:o,recovered:_},l);if(this.logger.info(`任务执行成功,成功信息:${JSON.stringify(h)}`),needRetryAdError({apiError:null==h?void 0:h.apiError,configuredAdTimeout:i._adTimeoutTime,errorRetryStrategy:this._errorRetryStrategy})&&!this._isForeground&&e._retryCount<this._maxRetryCount){var u;e._retryCount++,e._retryMsg=(null==h||null==(u=h.apiError)?void 0:u.errMsg)||"unknown";let t=`任务 ${o} 在后台失败,加入重试队列 (即将第 ${e._retryCount} 次重试, 最大重试次数 ${this._maxRetryCount}, 重试原因: ${e._retryMsg})`;this.logger.warn(t),h.recovered.retry=!0,h.recovered.count=e._retryCount,h.recovered.message=e._retryMsg,e._isResolved=!1,e._isRejected=!1,this._retryQueue.push(e)}else e._isResolved=!0;a(h),null==i||i.record(h)}catch(n){let s=Object.assign({id:o,apiError:n,recovered:_});this.logger.error(`任务执行失败, 继续下一个任务,错误信息:${JSON.stringify(s)}`),e._isRejected=!0;try{null==i||i.clear()}catch(e){this.logger.error("clear error: ",JSON.stringify(Object.assign({id:o,apiError:e})))}a(s),null==i||i.record(s),await r(t)}}),r={roundTasks:t.length};compose(t)(r,async e=>{this.logger.info("本轮活动队列已经清空",e),this._taskStack.length>0?Promise.resolve().then(()=>{this._compose()}):(this._isRunning=!1,this._currentTask=null,this._currentBatchTasks=[])})()}clearTasks(){if(this._currentTask){if(this._currentTask._isResolved||this._currentTask._isRejected){this._currentTask=null;return}try{this._currentTask.callbackCollection&&this._currentTask.callbackCollection.cancel&&this._currentTask.callbackCollection.cancel(),this._currentTask._isResolved=!0,this._currentTask.resolve()}catch(e){this.logger.error("clear current task error: ",e)}this._currentTask=null}this._currentBatchTasks.length>0&&(this._currentBatchTasks.forEach(e=>{if(e!==this._currentTask&&!e._isResolved&&!e._isRejected)try{e.callbackCollection&&e.callbackCollection.cancel&&e.callbackCollection.cancel(),e._isResolved=!0,e.resolve()}catch(e){this.logger.error("clear current batch task error: ",e)}}),this._currentBatchTasks=[]),this._taskStack.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.cancel))try{e.callbackCollection.cancel()}catch(e){this.logger.error("clear task error: ",e)}}),this._retryQueue.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.cancel))try{e.callbackCollection.cancel()}catch(e){this.logger.error("clear retry task error: ",e)}}),this._taskStack=[],this._retryQueue=[],this._isRunning=!1}getTaskCount(){return this._taskStack.filter(e=>!e._isResolved&&!e._isRejected).length+this._currentBatchTasks.filter(e=>e!==this._currentTask&&!e._isResolved&&!e._isRejected).length+(!this._currentTask||this._currentTask._isResolved||this._currentTask._isRejected?0:1)+this._retryQueue.filter(e=>!e._isResolved&&!e._isRejected).length}isRunning(){return this._isRunning}getCurrentTaskId(){var e;return(null==(e=this._currentTask)?void 0:e.id)||null}whenAllTasksComplete(){return new Promise(e=>{let t=null,r=()=>{let i=0===this._taskStack.length,s=!this._isRunning,n=null===this._currentTask,a=0===this._currentBatchTasks.length||this._currentBatchTasks.every(e=>e._isResolved||e._isRejected),o=0===this._retryQueue.length;i&&s&&n&&a&&o?(t&&clearTimeout(t),e()):t=setTimeout(r,500)};r()})}}const src_AdExecuteManager=AdExecuteManager;for(var __rspack_i in exports.AdExecuteManager=__webpack_exports__.AdExecuteManager,__webpack_exports__)-1===["AdExecuteManager"].indexOf(__rspack_i)&&(exports[__rspack_i]=__webpack_exports__[__rspack_i]);Object.defineProperty(exports,"__esModule",{value:!0});
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{Logger as e}from"@ad-execute-manager/helper";class t{static _instance=null;_taskStack=[];_currentBatchTasks=[];_isRunning=!1;_currentTask=null;_isForeground=!0;_appShowListener=null;_appHideListener=null;_enableVisibilityListener=!1;_maxRetryCount=1;_retryQueue=[];_errorRetryStrategy={timeout:!0,background:!0};constructor(t){this.logger=new e({prefix:"AdExecuteManager",enabled:!!(null==t?void 0:t.log)}),(null==t?void 0:t.errorRetryStrategy)&&(this._errorRetryStrategy=Object.assign({},this._errorRetryStrategy,null==t?void 0:t.errorRetryStrategy)),this._enableVisibilityListener=null==t?void 0:t.enableVisibilityListener,this._maxRetryCount=(null==t?void 0:t.maxRetryCount)??1,this._enableVisibilityListener&&this._initVisibilityListener()}initialize(e){return this}static getInstance(e){return t._instance||(t._instance=new t(e)),t._instance}static build(e){return t._instance||(t._instance=new t(e)),t._instance}static new(e){return new t(e)}static getSafeInstance(){return t._instance?t._instance:(this.logger.error("AdExecuteManager实例不存在"),null)}_initVisibilityListener(){!("u"<typeof tt)&&tt.onAppShow&&tt.onAppHide?(this._appShowListener=()=>{this._isForeground=!0,this._handleAppShow()},this._appHideListener=()=>{this._isForeground=!1,this._handleAppHide()},tt.onAppShow(this._appShowListener),tt.onAppHide(this._appHideListener),this.logger.info("前后台监听器已初始化")):this.logger.warn("tt API不可用,无法监听前后台状态")}_handleAppHide(){if(this._isRunning&&this._currentBatchTasks.length>0){let e=this._currentBatchTasks.filter(e=>{var t;return e.id!==(null==(t=this._currentTask)?void 0:t.id)&&!e._isResolved&&!e._isRejected});e.length>0&&(this.logger.info(`将 ${e.length} 个未执行的任务放回任务栈,任务ID: ${e.map(e=>e.id).join(",")}`),this._taskStack=[...e,...this._taskStack],this._currentBatchTasks=this._currentBatchTasks.filter(t=>!e.some(e=>e.id===t.id)))}}_handleAppShow(){this._retryQueue.length>0&&(this.logger.info(`应用进入前台:优先执行重试队列,任务数: ${this._retryQueue.length}, 任务ID: ${this._retryQueue.map(e=>e.id).join(",")}`),this._taskStack=[...this._retryQueue,...this._taskStack],this._retryQueue=[]),this._taskStack.length>0&&!this._isRunning&&(this.logger.info(`应用进入前台:恢复待执行任务数: ${this._taskStack.length}, 任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._compose())}destroyVisibilityListener(){this._appShowListener&&"u">typeof tt&&tt.offAppShow&&(tt.offAppShow(this._appShowListener),this._appShowListener=null),this._appHideListener&&"u">typeof tt&&tt.offAppHide&&(tt.offAppHide(this._appHideListener),this._appHideListener=null),this.logger.info("前后台监听器已销毁")}enableVisibilityListener(){this._enableVisibilityListener||(this._enableVisibilityListener=!0,this._initVisibilityListener()),this.logger.info("前后台监听器已启用")}disableVisibilityListener(){this._enableVisibilityListener&&(this._enableVisibilityListener=!1,this.destroyVisibilityListener()),this.logger.info("前后台监听器已禁用")}isVisibilityListenerEnabled(){return this._enableVisibilityListener}addTask(e,t){return e&&"function"==typeof e.ad?new Promise((i,r)=>{let s={adInstance:e,options:t.options??{},callbackCollection:t.collection??{},resolve:i,reject:r,id:`ad_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,_isResolved:!1,_isRejected:!1,_retryCount:0,_retryMsg:"ok"};this._taskStack.push(s),this._isRunning||this._compose()}):(this.logger.error("无效的广告实例 请正确实现.ad方法"),Promise.reject(Error("无效的广告实例")))}_compose(){if(0===this._taskStack.length){this._isRunning=!1,this._currentTask=null;return}if(!this._isForeground){this.logger.info(`应用处于后台,暂停任务执行,任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._isRunning=!1;return}this._isRunning=!0;let e=[...this._taskStack];this._taskStack=[],this._currentBatchTasks=e;let t=e.map(e=>async(t,i)=>{let{adInstance:r,options:s,callbackCollection:n,resolve:a,id:l,_retryCount:o,_retryMsg:c}=e,h={count:o,retry:o>0,message:c};if(e._isResolved||e._isRejected)return void await i(t);this._currentTask=e;try{let o=async e=>{await i(Object.assign({},t,e))},c=await r.initialize(s).ad({options:s,collection:n,recovered:h},o),u=Object.assign({id:l,recovered:h},c);if(this.logger.info(`任务执行成功,成功信息:${JSON.stringify(u)}`),function({apiError:e,configuredAdTimeout:t,errorRetryStrategy:i}){var r;return!!((null==i?void 0:i.timeout)&&(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&e.errMsg.startsWith("ad_show_timeout: normal")&&(null==e?void 0:e.timeout)==t)||!!((null==i?void 0:i.background)&&(null==(r=e)?void 0:r.errMsg)&&"string"==typeof r.errMsg&&(r.errMsg.startsWith("app in background is not support show ad")||r.errMsg.startsWith("other controller is presented")))}({apiError:null==u?void 0:u.apiError,configuredAdTimeout:r._adTimeoutTime,errorRetryStrategy:this._errorRetryStrategy})&&!this._isForeground&&e._retryCount<this._maxRetryCount){var _;e._retryCount++,e._retryMsg=(null==u||null==(_=u.apiError)?void 0:_.errMsg)||"unknown";let t=`任务 ${l} 在后台失败,加入重试队列 (即将第 ${e._retryCount} 次重试, 最大重试次数 ${this._maxRetryCount}, 重试原因: ${e._retryMsg})`;this.logger.warn(t),u.recovered.retry=!0,u.recovered.count=e._retryCount,u.recovered.message=e._retryMsg,e._isResolved=!1,e._isRejected=!1,this._retryQueue.push(e)}else e._isResolved=!0;a(u),null==r||r.record(u)}catch(n){let s=Object.assign({id:l,apiError:n,recovered:h});this.logger.error(`任务执行失败, 继续下一个任务,错误信息:${JSON.stringify(s)}`),e._isRejected=!0;try{null==r||r.clear()}catch(e){this.logger.error("clear error: ",JSON.stringify(Object.assign({id:l,apiError:e})))}a(s),null==r||r.record(s),await i(t)}}),i={roundTasks:t.length};t.map(e=>(t,i)=>async r=>await e(Object.assign({},t,r),i)).reduce((e,t)=>(i,r)=>e(i,t(i,r)))(i,async e=>{this.logger.info("本轮活动队列已经清空",e),this._taskStack.length>0?Promise.resolve().then(()=>{this._compose()}):(this._isRunning=!1,this._currentTask=null,this._currentBatchTasks=[])})()}clearTasks(){if(this._currentTask){if(this._currentTask._isResolved||this._currentTask._isRejected){this._currentTask=null;return}try{this._currentTask.callbackCollection&&this._currentTask.callbackCollection.onCancel&&this._currentTask.callbackCollection.onCancel(),this._currentTask._isResolved=!0,this._currentTask.resolve()}catch(e){this.logger.error("clear current task error: ",e)}this._currentTask=null}this._currentBatchTasks.length>0&&(this._currentBatchTasks.forEach(e=>{if(e!==this._currentTask&&!e._isResolved&&!e._isRejected)try{e.callbackCollection&&e.callbackCollection.onCancel&&e.callbackCollection.onCancel(),e._isResolved=!0,e.resolve()}catch(e){this.logger.error("clear current batch task error: ",e)}}),this._currentBatchTasks=[]),this._taskStack.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.onCancel))try{e.callbackCollection.onCancel()}catch(e){this.logger.error("clear task error: ",e)}}),this._retryQueue.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.onCancel))try{e.callbackCollection.onCancel()}catch(e){this.logger.error("clear retry task error: ",e)}}),this._taskStack=[],this._retryQueue=[],this._isRunning=!1}getTaskCount(){return this._taskStack.filter(e=>!e._isResolved&&!e._isRejected).length+this._currentBatchTasks.filter(e=>e!==this._currentTask&&!e._isResolved&&!e._isRejected).length+(!this._currentTask||this._currentTask._isResolved||this._currentTask._isRejected?0:1)+this._retryQueue.filter(e=>!e._isResolved&&!e._isRejected).length}isRunning(){return this._isRunning}getCurrentTaskId(){var e;return(null==(e=this._currentTask)?void 0:e.id)||null}whenAllTasksComplete(){return new Promise(e=>{let t=null,i=()=>{let r=0===this._taskStack.length,s=!this._isRunning,n=null===this._currentTask,a=0===this._currentBatchTasks.length||this._currentBatchTasks.every(e=>e._isResolved||e._isRejected),l=0===this._retryQueue.length;r&&s&&n&&a&&l?(t&&clearTimeout(t),e()):t=setTimeout(i,500)};i()})}}let i=t;export{i as AdExecuteManager};
1
+ import{Logger as e}from"@ad-execute-manager/logger";class t{static _instance=null;_taskStack=[];_currentBatchTasks=[];_isRunning=!1;_currentTask=null;_isForeground=!0;_appShowListener=null;_appHideListener=null;_enableVisibilityListener=!1;_maxRetryCount=1;_retryQueue=[];_errorRetryStrategy={timeout:!0,background:!0};constructor(t){this.logger=new e({prefix:"AdExecuteManager",enabled:!!(null==t?void 0:t.log)}),(null==t?void 0:t.errorRetryStrategy)&&(this._errorRetryStrategy=Object.assign({},this._errorRetryStrategy,null==t?void 0:t.errorRetryStrategy)),this._enableVisibilityListener=null==t?void 0:t.enableVisibilityListener,this._maxRetryCount=(null==t?void 0:t.maxRetryCount)??1,this._enableVisibilityListener&&this._initVisibilityListener()}initialize(e){return this}static getInstance(e){return t._instance||(t._instance=new t(e)),t._instance}static build(e){return t._instance||(t._instance=new t(e)),t._instance}static new(e){return new t(e)}static getSafeInstance(){return t._instance?t._instance:(this.logger.error("AdExecuteManager实例不存在"),null)}_initVisibilityListener(){!("u"<typeof tt)&&tt.onAppShow&&tt.onAppHide?(this._appShowListener=()=>{this._isForeground=!0,this._handleAppShow()},this._appHideListener=()=>{this._isForeground=!1,this._handleAppHide()},tt.onAppShow(this._appShowListener),tt.onAppHide(this._appHideListener),this.logger.info("前后台监听器已初始化")):this.logger.warn("tt API不可用,无法监听前后台状态")}_handleAppHide(){if(this._isRunning&&this._currentBatchTasks.length>0){let e=this._currentBatchTasks.filter(e=>{var t;return e.id!==(null==(t=this._currentTask)?void 0:t.id)&&!e._isResolved&&!e._isRejected});e.length>0&&(this.logger.info(`将 ${e.length} 个未执行的任务放回任务栈,任务ID: ${e.map(e=>e.id).join(",")}`),this._taskStack=[...e,...this._taskStack],this._currentBatchTasks=this._currentBatchTasks.filter(t=>!e.some(e=>e.id===t.id)))}}_handleAppShow(){this._retryQueue.length>0&&(this.logger.info(`应用进入前台:优先执行重试队列,任务数: ${this._retryQueue.length}, 任务ID: ${this._retryQueue.map(e=>e.id).join(",")}`),this._taskStack=[...this._retryQueue,...this._taskStack],this._retryQueue=[]),this._taskStack.length>0&&!this._isRunning&&(this.logger.info(`应用进入前台:恢复待执行任务数: ${this._taskStack.length}, 任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._compose())}destroyVisibilityListener(){this._appShowListener&&"u">typeof tt&&tt.offAppShow&&(tt.offAppShow(this._appShowListener),this._appShowListener=null),this._appHideListener&&"u">typeof tt&&tt.offAppHide&&(tt.offAppHide(this._appHideListener),this._appHideListener=null),this.logger.info("前后台监听器已销毁")}enableVisibilityListener(){this._enableVisibilityListener||(this._enableVisibilityListener=!0,this._initVisibilityListener()),this.logger.info("前后台监听器已启用")}disableVisibilityListener(){this._enableVisibilityListener&&(this._enableVisibilityListener=!1,this.destroyVisibilityListener()),this.logger.info("前后台监听器已禁用")}isVisibilityListenerEnabled(){return this._enableVisibilityListener}addTask(e,t){return e&&"function"==typeof e.ad?new Promise((i,r)=>{let s={adInstance:e,options:t.options??{},callbackCollection:t.collection??{},resolve:i,reject:r,id:`ad_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,_isResolved:!1,_isRejected:!1,_retryCount:0,_retryMsg:"ok"};this._taskStack.push(s),this._isRunning||this._compose()}):(this.logger.error("无效的广告实例 请正确实现.ad方法"),Promise.reject(Error("无效的广告实例")))}_compose(){if(0===this._taskStack.length){this._isRunning=!1,this._currentTask=null;return}if(!this._isForeground){this.logger.info(`应用处于后台,暂停任务执行,任务ID: ${this._taskStack.map(e=>e.id).join(",")}`),this._isRunning=!1;return}this._isRunning=!0;let e=[...this._taskStack];this._taskStack=[],this._currentBatchTasks=e;let t=e.map(e=>async(t,i)=>{let{adInstance:r,options:s,callbackCollection:n,resolve:a,id:l,_retryCount:o,_retryMsg:c}=e,h={count:o,retry:o>0,message:c};if(e._isResolved||e._isRejected)return void await i(t);this._currentTask=e;try{let o=async e=>{await i(Object.assign({},t,e))},c=await r.initialize(s).ad({options:s,collection:n,recovered:h},o),u=Object.assign({id:l,recovered:h},c);if(this.logger.info(`任务执行成功,成功信息:${JSON.stringify(u)}`),function({apiError:e,configuredAdTimeout:t,errorRetryStrategy:i}){var r;return!!((null==i?void 0:i.timeout)&&(null==e?void 0:e.errMsg)&&"string"==typeof e.errMsg&&e.errMsg.startsWith("ad_show_timeout: normal")&&(null==e?void 0:e.timeout)==t)||!!((null==i?void 0:i.background)&&(null==(r=e)?void 0:r.errMsg)&&"string"==typeof r.errMsg&&(r.errMsg.startsWith("app in background is not support show ad")||r.errMsg.startsWith("other controller is presented")))}({apiError:null==u?void 0:u.apiError,configuredAdTimeout:r._adTimeoutTime,errorRetryStrategy:this._errorRetryStrategy})&&!this._isForeground&&e._retryCount<this._maxRetryCount){var _;e._retryCount++,e._retryMsg=(null==u||null==(_=u.apiError)?void 0:_.errMsg)||"unknown";let t=`任务 ${l} 在后台失败,加入重试队列 (即将第 ${e._retryCount} 次重试, 最大重试次数 ${this._maxRetryCount}, 重试原因: ${e._retryMsg})`;this.logger.warn(t),u.recovered.retry=!0,u.recovered.count=e._retryCount,u.recovered.message=e._retryMsg,e._isResolved=!1,e._isRejected=!1,this._retryQueue.push(e)}else e._isResolved=!0;a(u),null==r||r.record(u)}catch(n){let s=Object.assign({id:l,apiError:n,recovered:h});this.logger.error(`任务执行失败, 继续下一个任务,错误信息:${JSON.stringify(s)}`),e._isRejected=!0;try{null==r||r.clear()}catch(e){this.logger.error("clear error: ",JSON.stringify(Object.assign({id:l,apiError:e})))}a(s),null==r||r.record(s),await i(t)}}),i={roundTasks:t.length};t.map(e=>(t,i)=>async r=>await e(Object.assign({},t,r),i)).reduce((e,t)=>(i,r)=>e(i,t(i,r)))(i,async e=>{this.logger.info("本轮活动队列已经清空",e),this._taskStack.length>0?Promise.resolve().then(()=>{this._compose()}):(this._isRunning=!1,this._currentTask=null,this._currentBatchTasks=[])})()}clearTasks(){if(this._currentTask){if(this._currentTask._isResolved||this._currentTask._isRejected){this._currentTask=null;return}try{this._currentTask.callbackCollection&&this._currentTask.callbackCollection.cancel&&this._currentTask.callbackCollection.cancel(),this._currentTask._isResolved=!0,this._currentTask.resolve()}catch(e){this.logger.error("clear current task error: ",e)}this._currentTask=null}this._currentBatchTasks.length>0&&(this._currentBatchTasks.forEach(e=>{if(e!==this._currentTask&&!e._isResolved&&!e._isRejected)try{e.callbackCollection&&e.callbackCollection.cancel&&e.callbackCollection.cancel(),e._isResolved=!0,e.resolve()}catch(e){this.logger.error("clear current batch task error: ",e)}}),this._currentBatchTasks=[]),this._taskStack.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.cancel))try{e.callbackCollection.cancel()}catch(e){this.logger.error("clear task error: ",e)}}),this._retryQueue.forEach(e=>{if(!e._isResolved&&!e._isRejected&&(e._isResolved=!0,e.resolve(),e.callbackCollection&&e.callbackCollection.cancel))try{e.callbackCollection.cancel()}catch(e){this.logger.error("clear retry task error: ",e)}}),this._taskStack=[],this._retryQueue=[],this._isRunning=!1}getTaskCount(){return this._taskStack.filter(e=>!e._isResolved&&!e._isRejected).length+this._currentBatchTasks.filter(e=>e!==this._currentTask&&!e._isResolved&&!e._isRejected).length+(!this._currentTask||this._currentTask._isResolved||this._currentTask._isRejected?0:1)+this._retryQueue.filter(e=>!e._isResolved&&!e._isRejected).length}isRunning(){return this._isRunning}getCurrentTaskId(){var e;return(null==(e=this._currentTask)?void 0:e.id)||null}whenAllTasksComplete(){return new Promise(e=>{let t=null,i=()=>{let r=0===this._taskStack.length,s=!this._isRunning,n=null===this._currentTask,a=0===this._currentBatchTasks.length||this._currentBatchTasks.every(e=>e._isResolved||e._isRejected),l=0===this._retryQueue.length;r&&s&&n&&a&&l?(t&&clearTimeout(t),e()):t=setTimeout(i,500)};i()})}}let i=t;export{i as AdExecuteManager};
@@ -80,14 +80,10 @@ export type CallbackCollection = {
80
80
  * 半途退出广告外部回调
81
81
  */
82
82
  halfway?: (ctx?: IExeCallbackArgs) => void;
83
- /**
84
- * 完成广告外部回调 不管看不看完
85
- */
86
- complete?: (ctx?: IExeCallbackArgs) => void;
87
83
  /**
88
84
  * 取消广告外部回调
89
85
  */
90
- onCancel?: (ctx?: IExeCallbackArgs) => void;
86
+ cancel?: (ctx?: IExeCallbackArgs) => void;
91
87
  /**
92
88
  * 展示广告外部回调
93
89
  */
@@ -115,6 +111,20 @@ export type RecoveredInfo = {
115
111
  */
116
112
  message: string;
117
113
  };
114
+ export type IApiError = {
115
+ /**
116
+ * 错误信息
117
+ */
118
+ errMsg?: string;
119
+ /**
120
+ * 错误码
121
+ */
122
+ errorCode?: number;
123
+ /**
124
+ * 错误信息
125
+ */
126
+ message?: string;
127
+ };
118
128
  export type ICallbackArgs = {
119
129
  /**
120
130
  * 广告执行场景
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ad-execute-manager/core",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Core functionality for ad execution management including AdExecuteManager, utility functions, and middleware composition.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -51,8 +51,8 @@
51
51
  "prepublishOnly": "npm run build"
52
52
  },
53
53
 
54
- "dependencies": {
55
- "@ad-execute-manager/helper": "^2.0.1"
54
+ "peerDependencies": {
55
+ "@ad-execute-manager/logger": "^2.0.2"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@babel/eslint-parser": "^7.28.5",