@maccesar/titools 5.1.1 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +69 -0
  2. package/README.md +112 -72
  3. package/agents/ti-pro.md +5 -1
  4. package/commands/ti-audit.md +5 -1
  5. package/docs/examples.md +91 -0
  6. package/docs/knowledge-index.md +57 -0
  7. package/lib/config.js +2 -0
  8. package/lib/downloader.js +1 -1
  9. package/package.json +4 -2
  10. package/skills/purgetss/references/multi-density-images.md +1 -1
  11. package/skills/ti-admob-unified/SKILL.md +58 -0
  12. package/skills/ti-admob-unified/agents/openai.yaml +4 -0
  13. package/skills/ti-admob-unified/assets/example/app.js +1207 -0
  14. package/skills/ti-admob-unified/assets/example/lib/ads.js +646 -0
  15. package/skills/ti-admob-unified/assets/example/library-usage.js +136 -0
  16. package/skills/ti-admob-unified/references/api-reference.md +615 -0
  17. package/skills/ti-admob-unified/references/banners.md +435 -0
  18. package/skills/ti-admob-unified/references/contributing.md +233 -0
  19. package/skills/ti-admob-unified/references/dependencies.md +91 -0
  20. package/skills/ti-admob-unified/references/fullscreen.md +238 -0
  21. package/skills/ti-admob-unified/references/game-monetization.md +148 -0
  22. package/skills/ti-admob-unified/references/getting-started.md +319 -0
  23. package/skills/ti-admob-unified/references/index.md +33 -0
  24. package/skills/ti-admob-unified/references/integration.md +87 -0
  25. package/skills/ti-admob-unified/references/library.md +220 -0
  26. package/skills/ti-admob-unified/references/mediation-parity.md +17 -0
  27. package/skills/ti-admob-unified/references/mediation.md +145 -0
  28. package/skills/ti-admob-unified/references/migration.md +259 -0
  29. package/skills/ti-admob-unified/references/module-changelog.md +84 -0
  30. package/skills/ti-admob-unified/references/module-license.txt +21 -0
  31. package/skills/ti-admob-unified/references/privacy.md +281 -0
  32. package/skills/ti-admob-unified/references/production.md +67 -0
  33. package/skills/ti-admob-unified/references/rewarded-interstitial.md +101 -0
  34. package/skills/ti-admob-unified/references/roadmap.md +143 -0
  35. package/skills/ti-admob-unified/references/source-notes.md +80 -0
  36. package/skills/ti-admob-unified/references/source-snapshot.json +644 -0
  37. package/skills/ti-admob-unified/references/third-party-notices.md +22 -0
  38. package/skills/ti-game/SKILL.md +31 -5
  39. package/skills/ti-game/references/api.md +36 -24
  40. package/skills/ti-game/references/debugging-performance.md +22 -7
  41. package/skills/ti-game/references/examples.md +113 -20
  42. package/skills/ti-game/references/input.md +101 -0
  43. package/skills/ti-game/references/patterns.md +56 -10
  44. package/skills/ti-game/references/physics.md +530 -0
  45. package/skills/ti-game/references/project-setup.md +131 -47
  46. package/skills/ti-game/references/recipes-action.md +149 -18
  47. package/skills/ti-game/references/recipes-adventure-effects.md +47 -4
  48. package/skills/ti-game/references/roadmap.md +11 -4
  49. package/skills/ti-game/references/source-notes.md +81 -0
  50. package/skills/ti-game/references/tilemaps.md +13 -4
  51. package/skills/ti-game-assets/SKILL.md +53 -0
  52. package/skills/ti-game-assets/agents/openai.yaml +4 -0
  53. package/skills/ti-game-assets/references/alpha.md +26 -0
  54. package/skills/ti-game-assets/references/art-direction.md +37 -0
  55. package/skills/ti-game-assets/references/integration.md +49 -0
  56. package/skills/ti-game-assets/references/manifest.example.json +429 -0
  57. package/skills/ti-game-assets/references/manifest.md +39 -0
  58. package/skills/ti-game-assets/references/offline-audio.md +33 -0
  59. package/skills/ti-game-assets/references/prompts.md +33 -0
  60. package/skills/ti-game-assets/references/repeating-textures.md +17 -0
  61. package/skills/ti-game-assets/references/responsible-ads.md +31 -0
  62. package/skills/ti-game-assets/references/sound-assets.md +42 -0
  63. package/skills/ti-game-assets/references/vector-sources.md +21 -0
  64. package/skills/ti-game-assets/scripts/alpha_tools.py +160 -0
  65. package/skills/ti-game-assets/scripts/requirements.txt +1 -0
  66. package/skills/ti-game-assets/scripts/validate_manifest.py +267 -0
  67. package/skills/ti-synthengine/SKILL.md +77 -67
  68. package/skills/ti-synthengine/assets/example/README.md +84 -0
  69. package/skills/ti-synthengine/assets/example/app.js +1178 -0
  70. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +83 -0
  71. package/skills/ti-synthengine/assets/example/lib/sequenceScore.js +25 -0
  72. package/skills/ti-synthengine/references/advanced-examples.md +174 -0
  73. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  74. package/skills/ti-synthengine/references/android-sim80-correction.json +162 -0
  75. package/skills/ti-synthengine/references/api.md +573 -153
  76. package/skills/ti-synthengine/references/audio-engine.md +272 -124
  77. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  78. package/skills/ti-synthengine/references/examples.md +355 -106
  79. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  80. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  81. package/skills/ti-synthengine/references/frontier-physical-validation.json +1918 -0
  82. package/skills/ti-synthengine/references/guide.md +426 -75
  83. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  84. package/skills/ti-synthengine/references/performance-review.json +1146 -0
  85. package/skills/ti-synthengine/references/physical-validation.json +1457 -0
  86. package/skills/ti-synthengine/references/recipes-interaction.md +549 -0
  87. package/skills/ti-synthengine/references/recipes.md +434 -420
  88. package/skills/ti-synthengine/references/recommendations.md +72 -85
  89. package/skills/ti-synthengine/references/sound-design.md +375 -155
  90. package/skills/ti-synthengine/references/source-notes.md +109 -0
  91. package/skills/ti-synthengine/references/source-snapshot.json +452 -0
  92. package/skills/ti-synthengine/references/stats-performance.json +2992 -0
  93. package/skills/ti-synthengine/references/stats-performance.md +82 -0
  94. package/skills/ti-synthengine/references/studio-validation.json +6202 -0
  95. package/skills/ti-synthengine/references/troubleshooting.md +123 -78
  96. package/skills/ti-synthengine/references/unified-bypass-performance.json +22425 -0
  97. package/skills/ti-synthengine/references/unified-validation.json +314 -0
  98. package/AGENTS-VERCEL-RESEARCH.md +0 -175
@@ -0,0 +1,646 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Copy-ready TiAdMobUnified integration.
5
+ *
6
+ * Alloy: app/lib/ads.js
7
+ * Classic: Resources/lib/ads.js
8
+ *
9
+ * The Google Mobile Ads SDK owns banner refresh. This library never creates a
10
+ * refresh timer and never changes banner visibility while pausing.
11
+ */
12
+
13
+ const Admob = require('ti.admob.unified')
14
+
15
+ const resources = new Set()
16
+
17
+ let startup = null
18
+ let startupOptions = {}
19
+ let gateResolved = false
20
+ let canRequest = false
21
+ let sdkReady = false
22
+ let privacyOperation = null
23
+ let inspectorOperation = null
24
+
25
+ function call(handler, event) {
26
+ if (typeof handler !== 'function') {
27
+ return
28
+ }
29
+
30
+ try {
31
+ handler(event || {})
32
+ } catch (error) {
33
+ Ti.API.error(`[ads] Event handler failed: ${error.message || error}`)
34
+ }
35
+ }
36
+
37
+ function waitForEvent(name, invoke) {
38
+ return new Promise(resolve => {
39
+ let settled = false
40
+
41
+ function finish(event) {
42
+ if (settled) {
43
+ return
44
+ }
45
+
46
+ settled = true
47
+ Admob.removeEventListener(name, finish)
48
+ resolve(event || {})
49
+ }
50
+
51
+ Admob.addEventListener(name, finish)
52
+
53
+ try {
54
+ invoke()
55
+ } catch (error) {
56
+ finish({ success: false, error: error.message || String(error) })
57
+ }
58
+ })
59
+ }
60
+
61
+ function synchronizeResources(method) {
62
+ Array.from(resources).forEach(resource => {
63
+ if (typeof resource[method] === 'function') {
64
+ resource[method]()
65
+ }
66
+ })
67
+ }
68
+
69
+ async function initializeIfAllowed() {
70
+ canRequest = Admob.canRequestAds()
71
+
72
+ if (!canRequest) {
73
+ return false
74
+ }
75
+
76
+ if (sdkReady) {
77
+ return true
78
+ }
79
+
80
+ const initialized = await waitForEvent('module_initialized', () => {
81
+ Admob.initialize(startupOptions.initialization || {})
82
+ })
83
+
84
+ sdkReady = initialized.success === true || initialized.success === 1
85
+ if (!sdkReady) {
86
+ Ti.API.warn(`[ads] Google Mobile Ads initialization failed: ${initialized.error || 'unknown error'}`)
87
+ }
88
+
89
+ return sdkReady
90
+ }
91
+
92
+ /**
93
+ * Runs UMP -> optional ATT -> eligibility -> SDK initialization once.
94
+ *
95
+ * options.consent: dictionary passed to requestConsent()
96
+ * options.requestTrackingAuthorization: true only when the app has a real ATT use case
97
+ * options.initialization: dictionary passed to initialize()
98
+ * Call start() while active. If UMP spans an iOS interruption, ATT waits for resumed.
99
+ */
100
+ function start(options) {
101
+ if (startup) {
102
+ return startup
103
+ }
104
+
105
+ startupOptions = options || {}
106
+ startup = (async () => {
107
+ const watchForeground = startupOptions.requestTrackingAuthorization === true && Ti.Platform.osname !== 'android'
108
+ let active = true
109
+ let resumeTracking = null
110
+ function onPause() { active = false }
111
+ function onResumed() {
112
+ active = true
113
+ if (resumeTracking) resumeTracking()
114
+ }
115
+ if (watchForeground) {
116
+ Ti.App.addEventListener('pause', onPause)
117
+ Ti.App.addEventListener('resumed', onResumed)
118
+ }
119
+ const consent = await waitForEvent('consent_complete', () => {
120
+ Admob.requestConsent(startupOptions.consent || {})
121
+ })
122
+
123
+ if (consent.success === false || consent.success === 0) {
124
+ Ti.API.warn(`[ads] UMP completed with an error: ${consent.error || 'unknown error'}`)
125
+ }
126
+
127
+ let tracking = null
128
+ if (startupOptions.requestTrackingAuthorization === true) {
129
+ if (watchForeground) {
130
+ if (!active) await new Promise(resolve => { resumeTracking = resolve })
131
+ Ti.App.removeEventListener('pause', onPause)
132
+ Ti.App.removeEventListener('resumed', onResumed)
133
+ }
134
+ tracking = await waitForEvent('tracking_authorization_completed', () => {
135
+ Admob.requestTrackingAuthorization()
136
+ })
137
+ }
138
+
139
+ await initializeIfAllowed()
140
+ gateResolved = true
141
+ synchronizeResources('sync')
142
+
143
+ return {
144
+ consent,
145
+ tracking,
146
+ canRequestAds: canRequest,
147
+ initialized: sdkReady
148
+ }
149
+ })()
150
+
151
+ return startup
152
+ }
153
+
154
+ function addListener(proxy, listeners, name, handler) {
155
+ if (!name || typeof handler !== 'function') {
156
+ return
157
+ }
158
+
159
+ proxy.addEventListener(name, handler)
160
+ listeners.push([name, handler])
161
+ }
162
+
163
+ function removeListeners(proxy, listeners) {
164
+ listeners.forEach(entry => proxy.removeEventListener(entry[0], entry[1]))
165
+ listeners.length = 0
166
+ }
167
+
168
+ function bannerProperties(options, adaptive) {
169
+ const properties = {
170
+ adUnitId: options.adUnitId,
171
+ width: options.width || Ti.UI.FILL
172
+ }
173
+
174
+ for (const key of ['keywords', 'contentUrl', 'requestAgent', 'extras']) {
175
+ if (options[key] !== undefined) {
176
+ properties[key] = options[key]
177
+ }
178
+ }
179
+
180
+ if (adaptive) {
181
+ if (Ti.Platform && Ti.Platform.osname !== 'android') properties.height = Ti.UI.FILL
182
+ properties.adaptiveType = options.adaptiveType || Admob.ADAPTIVE_ANCHORED
183
+ for (const key of ['maxHeight', 'collapsible']) {
184
+ if (options[key] !== undefined) {
185
+ properties[key] = options[key]
186
+ }
187
+ }
188
+ } else {
189
+ properties.adSize = options.adSize || Admob.BANNER
190
+ if (options.customAdSize !== undefined) {
191
+ properties.customAdSize = options.customAdSize
192
+ }
193
+ }
194
+
195
+ return properties
196
+ }
197
+
198
+ function createBannerPlacement(options, adaptive) {
199
+ if (!options || !options.host || !options.adUnitId) {
200
+ throw new Error('A banner requires host and adUnitId')
201
+ }
202
+
203
+ const host = options.host
204
+ const content = options.content
205
+ const reservedHeight = Number(options.reservedHeight)
206
+
207
+ if (!Number.isFinite(reservedHeight) || reservedHeight <= 0) {
208
+ throw new Error('A banner requires a positive reservedHeight in dp')
209
+ }
210
+
211
+ let proxy = null
212
+ let listeners = []
213
+ let destroyed = false
214
+ let locallyPaused = options.paused === true
215
+
216
+ function reserve(height) {
217
+ const dimension = `${Math.max(0, Number(height) || 0)}dp`
218
+ host.height = dimension
219
+ if (content) {
220
+ content.bottom = dimension
221
+ }
222
+ }
223
+
224
+ function detach(destroyNative) {
225
+ if (!proxy) {
226
+ return
227
+ }
228
+
229
+ const target = proxy
230
+ proxy = null
231
+ removeListeners(target, listeners)
232
+
233
+ if (destroyNative) {
234
+ target.destroy()
235
+ }
236
+
237
+ try {
238
+ host.remove(target)
239
+ } catch (error) {
240
+ Ti.API.debug(`[ads] Banner was already detached: ${error.message || error}`)
241
+ }
242
+ }
243
+
244
+ function onLoaded(event) {
245
+ const actualHeight = Number(event.height)
246
+ reserve(actualHeight > 0 ? actualHeight : reservedHeight)
247
+ call(options.onLoaded, event)
248
+ }
249
+
250
+ function onFailedToLoad(event) {
251
+ detach(true)
252
+ if (options.collapseOnFailure !== false) {
253
+ reserve(0)
254
+ }
255
+ call(options.onFailedToLoad, event)
256
+ }
257
+
258
+ function onDestroyed(event) {
259
+ detach(false)
260
+ reserve(0)
261
+ call(options.onDestroyed, event)
262
+ }
263
+
264
+ function attachForwarder(name, optionName) {
265
+ addListener(proxy, listeners, name, event => call(options[optionName], event))
266
+ }
267
+
268
+ const placement = {
269
+ sync() {
270
+ if (destroyed || locallyPaused || proxy) {
271
+ return
272
+ }
273
+
274
+ if (!canRequest || !sdkReady) {
275
+ if (gateResolved) {
276
+ reserve(0)
277
+ }
278
+ return
279
+ }
280
+
281
+ reserve(reservedHeight)
282
+ proxy = adaptive
283
+ ? Admob.createAdaptiveBanner(bannerProperties(options, true))
284
+ : Admob.createBanner(bannerProperties(options, false))
285
+
286
+ addListener(proxy, listeners, Admob.AD_LOADED, onLoaded)
287
+ addListener(proxy, listeners, Admob.AD_FAILED_TO_LOAD, onFailedToLoad)
288
+ addListener(proxy, listeners, Admob.AD_DESTROYED, onDestroyed)
289
+ attachForwarder(Admob.AD_CLICKED, 'onClicked')
290
+ attachForwarder(Admob.AD_IMPRESSION, 'onImpression')
291
+ attachForwarder(Admob.AD_OPENED, 'onOpened')
292
+ attachForwarder(Admob.AD_CLOSED, 'onClosed')
293
+
294
+ if (adaptive && Ti.Platform && Ti.Platform.osname !== 'android') {
295
+ const target = proxy
296
+ const anchored = !options.adaptiveType || options.adaptiveType === Admob.ADAPTIVE_ANCHORED
297
+ let measuredWidth = 0
298
+ function prepareSize(width) {
299
+ if (!anchored || width <= 0 || measuredWidth === width) return false
300
+ measuredWidth = width
301
+ const height = Admob.getAnchoredAdaptiveBannerSize(width).height
302
+ const changed = host.height !== `${height}dp`
303
+ reserve(height)
304
+ return changed
305
+ }
306
+ prepareSize(host.rect ? host.rect.width : 0)
307
+ function loadAfterLayout() {
308
+ if (destroyed || proxy !== target || target.rect.width <= 0 || target.rect.height <= 0) return
309
+ if (prepareSize(target.rect.width)) return
310
+ target.removeEventListener('postlayout', loadAfterLayout)
311
+ target.load()
312
+ }
313
+ addListener(target, listeners, 'postlayout', loadAfterLayout)
314
+ host.add(target)
315
+ } else {
316
+ host.add(proxy)
317
+ proxy.load()
318
+ }
319
+ },
320
+
321
+ pause() {
322
+ if (destroyed || locallyPaused) {
323
+ return
324
+ }
325
+
326
+ locallyPaused = true
327
+ if (proxy) {
328
+ proxy.pause()
329
+ }
330
+ },
331
+
332
+ resume() {
333
+ if (destroyed || !locallyPaused) {
334
+ return
335
+ }
336
+
337
+ locallyPaused = false
338
+ if (proxy) {
339
+ proxy.resume()
340
+ }
341
+ placement.sync()
342
+ },
343
+
344
+ rebuild() {
345
+ if (destroyed) {
346
+ return
347
+ }
348
+
349
+ detach(true)
350
+ reserve(reservedHeight)
351
+ placement.sync()
352
+ },
353
+
354
+ retry() {
355
+ placement.rebuild()
356
+ },
357
+
358
+ authorizationChanged() {
359
+ if (destroyed) {
360
+ return
361
+ }
362
+
363
+ detach(true)
364
+ reserve(canRequest && sdkReady ? reservedHeight : 0)
365
+ placement.sync()
366
+ },
367
+
368
+ isLoaded() {
369
+ return Boolean(proxy && proxy.isLoaded())
370
+ },
371
+
372
+ destroy() {
373
+ if (destroyed) {
374
+ return
375
+ }
376
+
377
+ destroyed = true
378
+ resources.delete(placement)
379
+ detach(true)
380
+ reserve(0)
381
+ }
382
+ }
383
+
384
+ resources.add(placement)
385
+ reserve(reservedHeight)
386
+ placement.sync()
387
+ return placement
388
+ }
389
+
390
+ function createBanner(options) {
391
+ return createBannerPlacement(options, false)
392
+ }
393
+
394
+ function createAdaptiveBanner(options) {
395
+ return createBannerPlacement(options, true)
396
+ }
397
+
398
+ const fullscreenEvents = [
399
+ ['AD_LOADED', 'onLoaded'],
400
+ ['AD_FAILED_TO_LOAD', 'onFailedToLoad'],
401
+ ['AD_OPENED', 'onOpened'],
402
+ ['AD_SHOWED_FULLSCREEN_CONTENT', 'onShowed'],
403
+ ['AD_CLOSED', 'onClosed'],
404
+ ['AD_CLICKED', 'onClicked'],
405
+ ['AD_IMPRESSION', 'onImpression'],
406
+ ['AD_FAILED_TO_SHOW', 'onFailedToShow'],
407
+ ['AD_REWARDED', 'onRewarded'],
408
+ ['AD_DESTROYED', 'onDestroyed']
409
+ ]
410
+
411
+ function fullscreenProperties(options) {
412
+ const properties = {
413
+ adUnitId: options.adUnitId,
414
+ autoReload: options.autoReload === true
415
+ }
416
+
417
+ for (const key of ['keywords', 'requestAgent', 'extras']) {
418
+ if (options[key] !== undefined) {
419
+ properties[key] = options[key]
420
+ }
421
+ }
422
+
423
+ return properties
424
+ }
425
+
426
+ // Shared by the managers and the raw-API playground. Rotation alone does no work.
427
+ function createFullscreenSizeGuard(getSize) {
428
+ let requestedSize = null
429
+ function sizeKey() {
430
+ const geometry = getSize()
431
+ // Window.size can change while Android restores bars after a fullscreen ad.
432
+ // Outer window bounds stay stable and still track rotation and split view.
433
+ const rect = geometry && geometry.rect
434
+ const size = rect && rect.width > 0 && rect.height > 0
435
+ ? rect : (geometry && geometry.size) || geometry
436
+ return size && size.width > 0 && size.height > 0
437
+ ? `${Math.round(size.width)}x${Math.round(size.height)}` : null
438
+ }
439
+ return {
440
+ recordLoad() { requestedSize = sizeKey() },
441
+ show(present, reload) {
442
+ const currentSize = sizeKey()
443
+ if (currentSize && currentSize !== requestedSize) {
444
+ reload()
445
+ return false
446
+ }
447
+ present()
448
+ return true
449
+ }
450
+ }
451
+ }
452
+
453
+ function createFullscreen(options, factoryName) {
454
+ if (!options || !options.adUnitId) {
455
+ throw new Error(`${factoryName} requires adUnitId`)
456
+ }
457
+
458
+ let proxy = null
459
+ let listeners = []
460
+ let destroyed = false
461
+ let loadRequested = options.autoLoad === true
462
+ let loading = false
463
+ const sizeGuard = createFullscreenSizeGuard(() => options.window || Ti.UI.currentWindow)
464
+
465
+ function detach(destroyNative) {
466
+ if (!proxy) {
467
+ return
468
+ }
469
+
470
+ const target = proxy
471
+ proxy = null
472
+ loading = false
473
+ removeListeners(target, listeners)
474
+ if (destroyNative) {
475
+ target.destroy()
476
+ }
477
+ }
478
+
479
+ const manager = {
480
+ sync() {
481
+ if (destroyed || proxy || !loadRequested || !canRequest || !sdkReady) {
482
+ return
483
+ }
484
+
485
+ proxy = Admob[factoryName](fullscreenProperties(options))
486
+
487
+ fullscreenEvents.forEach(entry => {
488
+ const eventName = Admob[entry[0]]
489
+ if (!eventName) {
490
+ return
491
+ }
492
+
493
+ addListener(proxy, listeners, eventName, event => {
494
+ if (entry[0] === 'AD_LOADED' || entry[0] === 'AD_FAILED_TO_LOAD') loading = false
495
+ if (entry[0] === 'AD_CLOSED' && options.autoReload === true) {
496
+ loading = true
497
+ sizeGuard.recordLoad()
498
+ }
499
+ if (entry[0] === 'AD_CLOSED' && options.autoReload !== true) {
500
+ loadRequested = false
501
+ }
502
+ if (entry[0] === 'AD_FAILED_TO_SHOW') {
503
+ loadRequested = false
504
+ }
505
+ if (entry[0] === 'AD_DESTROYED') {
506
+ detach(false)
507
+ call(options[entry[1]], event)
508
+ return
509
+ }
510
+ call(options[entry[1]], event)
511
+ })
512
+ })
513
+
514
+ loading = true
515
+ sizeGuard.recordLoad()
516
+ proxy.load()
517
+ },
518
+
519
+ load() {
520
+ if (destroyed || loading) {
521
+ return false
522
+ }
523
+
524
+ loadRequested = true
525
+ if (proxy) {
526
+ loading = true
527
+ sizeGuard.recordLoad()
528
+ proxy.load()
529
+ } else {
530
+ manager.sync()
531
+ }
532
+ return true
533
+ },
534
+
535
+ show() {
536
+ if (!proxy || loading || !proxy.isLoaded()) {
537
+ return false
538
+ }
539
+
540
+ return sizeGuard.show(() => proxy.show(), () => manager.retry())
541
+ },
542
+
543
+ isLoaded() {
544
+ return Boolean(proxy && proxy.isLoaded())
545
+ },
546
+
547
+ retry() {
548
+ if (destroyed) {
549
+ return false
550
+ }
551
+
552
+ detach(true)
553
+ loadRequested = true
554
+ manager.sync()
555
+ return true
556
+ },
557
+
558
+ authorizationChanged() {
559
+ if (destroyed) {
560
+ return
561
+ }
562
+
563
+ detach(true)
564
+ manager.sync()
565
+ },
566
+
567
+ destroy() {
568
+ if (destroyed) {
569
+ return
570
+ }
571
+
572
+ destroyed = true
573
+ resources.delete(manager)
574
+ detach(true)
575
+ }
576
+ }
577
+
578
+ resources.add(manager)
579
+ manager.sync()
580
+ return manager
581
+ }
582
+
583
+ function createInterstitial(options) {
584
+ return createFullscreen(options, 'createInterstitial')
585
+ }
586
+
587
+ function createRewarded(options) {
588
+ return createFullscreen(options, 'createRewarded')
589
+ }
590
+
591
+ function createRewardedInterstitial(options) {
592
+ return createFullscreen(options, 'createRewardedInterstitial')
593
+ }
594
+
595
+ function createAppOpen(options) {
596
+ return createFullscreen(options, 'createAppOpen')
597
+ }
598
+
599
+ function showPrivacyOptions() {
600
+ if (privacyOperation) return privacyOperation
601
+ privacyOperation = (async () => {
602
+ const result = await waitForEvent('privacy_options_dismissed', () => {
603
+ Admob.presentPrivacyOptions({})
604
+ })
605
+
606
+ await initializeIfAllowed()
607
+ synchronizeResources('authorizationChanged')
608
+ return result
609
+ })().finally(() => { privacyOperation = null })
610
+ return privacyOperation
611
+ }
612
+
613
+ function isPrivacyOptionsRequired() {
614
+ return Admob.isPrivacyOptionsRequired()
615
+ }
616
+
617
+ function openAdInspector() {
618
+ if (inspectorOperation) return inspectorOperation
619
+ inspectorOperation = waitForEvent('ad_inspector_closed', () => Admob.openAdInspector())
620
+ .finally(() => { inspectorOperation = null })
621
+ return inspectorOperation
622
+ }
623
+
624
+ function isReady() {
625
+ return canRequest && sdkReady
626
+ }
627
+
628
+ function destroyAll() {
629
+ Array.from(resources).forEach(resource => resource.destroy())
630
+ }
631
+
632
+ module.exports = {
633
+ start,
634
+ isReady,
635
+ isPrivacyOptionsRequired,
636
+ showPrivacyOptions,
637
+ openAdInspector,
638
+ createBanner,
639
+ createAdaptiveBanner,
640
+ createFullscreenSizeGuard,
641
+ createInterstitial,
642
+ createRewarded,
643
+ createRewardedInterstitial,
644
+ createAppOpen,
645
+ destroyAll
646
+ }