@chipmobilesdk/rn-ads 0.3.0 → 0.5.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/CHANGELOG.md +66 -1
- package/README.md +881 -771
- package/package.json +49 -49
- package/skills/sdk-rn-ads/SKILL.md +274 -240
- package/src/config/types.ts +18 -0
- package/src/core/adsInstance.ts +1933 -1670
- package/src/core/consentFlow.ts +14 -1
- package/src/core/initMachine.ts +13 -0
- package/src/core/placementMachine.ts +12 -2
- package/src/core/privacyGate.ts +10 -1
- package/src/engine/admobEngine.ts +33 -2
- package/src/engine/port.ts +30 -2
- package/src/index.ts +103 -101
- package/src/react/AdsBanner.tsx +340 -337
- package/src/testing/index.ts +106 -4
package/src/core/consentFlow.ts
CHANGED
|
@@ -34,6 +34,7 @@ export const INITIAL_CONSENT: ConsentSnapshot = {
|
|
|
34
34
|
state: 'undetermined',
|
|
35
35
|
canRequestAds: false,
|
|
36
36
|
isFormAvailable: false,
|
|
37
|
+
privacyOptionsRequirement: 'unknown',
|
|
37
38
|
error: null,
|
|
38
39
|
};
|
|
39
40
|
|
|
@@ -59,6 +60,7 @@ export function normalizeConsent(info: EngineConsentInfo): ConsentSnapshot {
|
|
|
59
60
|
state,
|
|
60
61
|
canRequestAds: info.canRequestAds === true,
|
|
61
62
|
isFormAvailable: info.isFormAvailable === true,
|
|
63
|
+
privacyOptionsRequirement: info.privacyOptions,
|
|
62
64
|
error: null,
|
|
63
65
|
};
|
|
64
66
|
}
|
|
@@ -70,9 +72,19 @@ export function normalizeConsent(info: EngineConsentInfo): ConsentSnapshot {
|
|
|
70
72
|
* There is no failure mode in which "the flow broke" should mean "go ahead", and
|
|
71
73
|
* making that structural rather than conditional means no future edit can
|
|
72
74
|
* accidentally reintroduce the inference.
|
|
75
|
+
*
|
|
76
|
+
* The privacy-options requirement is `unknown` for the same reason: a broken
|
|
77
|
+
* flow has no provider verdict to forward, and reporting `not_required` would be
|
|
78
|
+
* the package deciding the user has no right to change their mind (FR-150).
|
|
73
79
|
*/
|
|
74
80
|
export function consentFailure(error: AdsError): ConsentSnapshot {
|
|
75
|
-
return {
|
|
81
|
+
return {
|
|
82
|
+
state: 'error',
|
|
83
|
+
canRequestAds: false,
|
|
84
|
+
isFormAvailable: false,
|
|
85
|
+
privacyOptionsRequirement: 'unknown',
|
|
86
|
+
error,
|
|
87
|
+
};
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
export function toConsentError(cause: unknown, message: string): AdsError {
|
|
@@ -161,6 +173,7 @@ export function createConsentPortGuard(port: ConsentPort | undefined): ConsentPo
|
|
|
161
173
|
return {
|
|
162
174
|
requestInfoUpdate: unavailable,
|
|
163
175
|
showFormIfRequired: unavailable,
|
|
176
|
+
showPrivacyOptionsForm: unavailable,
|
|
164
177
|
getInfo: unavailable,
|
|
165
178
|
reset: () => undefined,
|
|
166
179
|
};
|
package/src/core/initMachine.ts
CHANGED
|
@@ -23,6 +23,13 @@ export type InitEvent =
|
|
|
23
23
|
| { readonly type: 'UNDECIDE' }
|
|
24
24
|
| { readonly type: 'ENABLE' }
|
|
25
25
|
| { readonly type: 'SUCCEED' }
|
|
26
|
+
/**
|
|
27
|
+
* Back to `ready` with no native call, because the provider was initialized
|
|
28
|
+
* earlier and nothing has torn it down since (FR-154). The instance decides
|
|
29
|
+
* whether that holds; this machine only refuses to resume from a state a
|
|
30
|
+
* fresh start could not leave either.
|
|
31
|
+
*/
|
|
32
|
+
| { readonly type: 'RESUME' }
|
|
26
33
|
| { readonly type: 'FAIL'; readonly error: AdsError };
|
|
27
34
|
|
|
28
35
|
export interface InitSnapshot {
|
|
@@ -165,6 +172,12 @@ export function initReducer(state: InitSnapshot, event: InitEvent): InitSnapshot
|
|
|
165
172
|
// resurrect a state the app deliberately left.
|
|
166
173
|
return state.status === 'initializing' ? at('ready') : state;
|
|
167
174
|
|
|
175
|
+
case 'RESUME':
|
|
176
|
+
// Same guard as START, for the same reason: `disabled`, `undecided` and
|
|
177
|
+
// `unavailable` are not left by a gate reopening. `canStart` excludes
|
|
178
|
+
// them, and `initializing`, whose own outcome is still on its way.
|
|
179
|
+
return canStart(state.status) ? at('ready') : state;
|
|
180
|
+
|
|
168
181
|
case 'FAIL':
|
|
169
182
|
return state.status === 'initializing' ? at('failed', { error: event.error }) : state;
|
|
170
183
|
|
|
@@ -40,9 +40,19 @@ export const initialPlacement: PlacementSnapshot = {
|
|
|
40
40
|
correlationId: null,
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* A load is only legal from a settled state; `loading` is where FR-029 bites.
|
|
45
|
+
* `throttled` is settled too: it records that the last request was refused, and
|
|
46
|
+
* the throttle itself decides whether the next one may proceed.
|
|
47
|
+
*/
|
|
44
48
|
export function canLoad(state: PlacementState): boolean {
|
|
45
|
-
return
|
|
49
|
+
return (
|
|
50
|
+
state === 'idle' ||
|
|
51
|
+
state === 'failed' ||
|
|
52
|
+
state === 'consumed' ||
|
|
53
|
+
state === 'ready' ||
|
|
54
|
+
state === 'throttled'
|
|
55
|
+
);
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
/** Only a ready ad may be shown. Everything else is a determinate refusal (FR-028). */
|
package/src/core/privacyGate.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { PrivacyBlockReason, PrivacyOptions } from '../config/types';
|
|
18
|
-
import type { EnginePrivacy } from '../engine/port';
|
|
18
|
+
import type { EnginePrivacy, EngineRequestOptions } from '../engine/port';
|
|
19
19
|
|
|
20
20
|
export type GateDecision =
|
|
21
21
|
| { readonly allowed: true }
|
|
@@ -83,3 +83,12 @@ export function toEnginePrivacy(
|
|
|
83
83
|
testDeviceIds,
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* What every ad request carries. Unset means personalized, matching the
|
|
89
|
+
* documented default of `PrivacyOptions.personalizedAds`; only an explicit
|
|
90
|
+
* `false` opts out.
|
|
91
|
+
*/
|
|
92
|
+
export function toEngineRequest(privacy: PrivacyOptions | null): EngineRequestOptions {
|
|
93
|
+
return { personalizedAds: privacy?.personalizedAds !== false };
|
|
94
|
+
}
|
|
@@ -27,6 +27,7 @@ import type {
|
|
|
27
27
|
EngineConsentInfo,
|
|
28
28
|
EngineConsentOptions,
|
|
29
29
|
EnginePrivacy,
|
|
30
|
+
EngineRequestOptions,
|
|
30
31
|
} from './port';
|
|
31
32
|
|
|
32
33
|
/** The slice of the bridge this adapter uses. Kept local so nothing else sees it. */
|
|
@@ -61,6 +62,7 @@ interface ProviderModule {
|
|
|
61
62
|
interface ProviderConsent {
|
|
62
63
|
requestInfoUpdate(options?: Record<string, unknown>): Promise<ProviderConsentInfo>;
|
|
63
64
|
loadAndShowConsentFormIfRequired(): Promise<ProviderConsentInfo>;
|
|
65
|
+
showPrivacyOptionsForm(): Promise<ProviderConsentInfo>;
|
|
64
66
|
getConsentInfo(): Promise<ProviderConsentInfo>;
|
|
65
67
|
reset(): void;
|
|
66
68
|
}
|
|
@@ -69,6 +71,7 @@ interface ProviderConsentInfo {
|
|
|
69
71
|
status?: string;
|
|
70
72
|
canRequestAds?: boolean;
|
|
71
73
|
isConsentFormAvailable?: boolean;
|
|
74
|
+
privacyOptionsRequirementStatus?: string;
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
/**
|
|
@@ -119,9 +122,25 @@ function toEngineConsentInfo(info: ProviderConsentInfo): EngineConsentInfo {
|
|
|
119
122
|
status: normalized,
|
|
120
123
|
canRequestAds: info.canRequestAds === true,
|
|
121
124
|
isFormAvailable: info.isConsentFormAvailable === true,
|
|
125
|
+
privacyOptions: toEnginePrivacyOptions(info.privacyOptionsRequirementStatus),
|
|
122
126
|
};
|
|
123
127
|
}
|
|
124
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Same rule as the status: an unrecognized value is `unknown`, never a guess in
|
|
131
|
+
* either direction (FR-150).
|
|
132
|
+
*/
|
|
133
|
+
function toEnginePrivacyOptions(value: string | undefined): EngineConsentInfo['privacyOptions'] {
|
|
134
|
+
switch (String(value ?? 'UNKNOWN').toUpperCase()) {
|
|
135
|
+
case 'REQUIRED':
|
|
136
|
+
return 'required';
|
|
137
|
+
case 'NOT_REQUIRED':
|
|
138
|
+
return 'not_required';
|
|
139
|
+
default:
|
|
140
|
+
return 'unknown';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
125
144
|
function loadProvider(): ProviderModule | null {
|
|
126
145
|
try {
|
|
127
146
|
return require('react-native-google-mobile-ads') as ProviderModule;
|
|
@@ -209,7 +228,11 @@ export function createAdMobEngine(): AdsEngine {
|
|
|
209
228
|
await mobileAds.initialize();
|
|
210
229
|
},
|
|
211
230
|
|
|
212
|
-
async createFullScreen(
|
|
231
|
+
async createFullScreen(
|
|
232
|
+
format: FullScreenFormat,
|
|
233
|
+
adUnitId: string,
|
|
234
|
+
request?: EngineRequestOptions,
|
|
235
|
+
) {
|
|
213
236
|
const module = getProvider();
|
|
214
237
|
if (!module) {
|
|
215
238
|
throw new Error('provider_missing');
|
|
@@ -224,7 +247,7 @@ export function createAdMobEngine(): AdsEngine {
|
|
|
224
247
|
const ad = factory.createForAdRequest(adUnitId, {
|
|
225
248
|
// The consumer-facing polarity is `personalizedAds`; the provider's
|
|
226
249
|
// is the inverse. The flip lives here, next to the API needing it.
|
|
227
|
-
requestNonPersonalizedAdsOnly: false,
|
|
250
|
+
requestNonPersonalizedAdsOnly: request?.personalizedAds === false,
|
|
228
251
|
});
|
|
229
252
|
|
|
230
253
|
counter += 1;
|
|
@@ -362,6 +385,14 @@ function createAdMobConsent(getProvider: () => ProviderModule | null): ConsentPo
|
|
|
362
385
|
return toEngineConsentInfo(info);
|
|
363
386
|
},
|
|
364
387
|
|
|
388
|
+
async showPrivacyOptionsForm() {
|
|
389
|
+
// Present in the pinned bridge 16.0.3, so no range change (FR-155).
|
|
390
|
+
// Resolves with the consent information as it stands once the form
|
|
391
|
+
// closes, whether the user changed anything or not.
|
|
392
|
+
const info = await requireConsent().showPrivacyOptionsForm();
|
|
393
|
+
return toEngineConsentInfo(info);
|
|
394
|
+
},
|
|
395
|
+
|
|
365
396
|
async getInfo() {
|
|
366
397
|
return toEngineConsentInfo(await requireConsent().getConsentInfo());
|
|
367
398
|
},
|
package/src/engine/port.ts
CHANGED
|
@@ -23,6 +23,17 @@ export interface EnginePrivacy {
|
|
|
23
23
|
readonly testDeviceIds?: readonly string[];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Privacy that applies to each ad request rather than to initialization.
|
|
28
|
+
*
|
|
29
|
+
* `personalizedAds` is here, not only in `EnginePrivacy`, because the provider
|
|
30
|
+
* reads it per request and `updatePrivacy` may change it without
|
|
31
|
+
* reinitializing: a request must carry the value current at request time.
|
|
32
|
+
*/
|
|
33
|
+
export interface EngineRequestOptions {
|
|
34
|
+
readonly personalizedAds: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
/**
|
|
27
38
|
* Provider callbacks, normalized to the vocabulary the core state machines use.
|
|
28
39
|
* `rewarded` and `dismissed` are separate members because they are separate
|
|
@@ -52,6 +63,8 @@ export interface EngineConsentInfo {
|
|
|
52
63
|
readonly status: 'unknown' | 'required' | 'not_required' | 'obtained';
|
|
53
64
|
readonly canRequestAds: boolean;
|
|
54
65
|
readonly isFormAvailable: boolean;
|
|
66
|
+
/** Whether the provider requires a "change my choice" entry point (FR-150). */
|
|
67
|
+
readonly privacyOptions: 'unknown' | 'required' | 'not_required';
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
export interface EngineConsentOptions {
|
|
@@ -76,6 +89,13 @@ export interface ConsentPort {
|
|
|
76
89
|
requestInfoUpdate(options: EngineConsentOptions): Promise<EngineConsentInfo>;
|
|
77
90
|
/** Presents the provider's form if one is required; a no-op otherwise. */
|
|
78
91
|
showFormIfRequired(): Promise<EngineConsentInfo>;
|
|
92
|
+
/**
|
|
93
|
+
* Presents the provider's privacy options form, through which a user changes
|
|
94
|
+
* an answer already given (FR-151). Resolves when the form closes, whether or
|
|
95
|
+
* not anything changed; rejects if it could not be presented. The caller has
|
|
96
|
+
* already checked the requirement, so the adapter does not re-check.
|
|
97
|
+
*/
|
|
98
|
+
showPrivacyOptionsForm(): Promise<EngineConsentInfo>;
|
|
79
99
|
/** Last known information without contacting the network. */
|
|
80
100
|
getInfo(): Promise<EngineConsentInfo>;
|
|
81
101
|
/** Clears the stored decision. Inert in production by configuration. */
|
|
@@ -99,8 +119,16 @@ export interface AdsEngine {
|
|
|
99
119
|
*/
|
|
100
120
|
initialize(privacy: EnginePrivacy): Promise<void>;
|
|
101
121
|
|
|
102
|
-
/**
|
|
103
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Creates and begins loading one full-screen ad. Resolves on request, not on
|
|
124
|
+
* load. `request` is optional so engines written against 0.4.0 still satisfy
|
|
125
|
+
* the port; an engine that ignores it requests personalized ads.
|
|
126
|
+
*/
|
|
127
|
+
createFullScreen(
|
|
128
|
+
format: FullScreenFormat,
|
|
129
|
+
adUnitId: string,
|
|
130
|
+
request?: EngineRequestOptions,
|
|
131
|
+
): Promise<EngineAdHandle>;
|
|
104
132
|
|
|
105
133
|
/** Presents a loaded ad. Rejects if the provider refuses to present. */
|
|
106
134
|
show(handle: EngineAdHandle): Promise<void>;
|
package/src/index.ts
CHANGED
|
@@ -1,101 +1,103 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @chipmobilesdk/rn-ads — reusable advertising capability for
|
|
3
|
-
* ChipMobileSdk-family React Native apps.
|
|
4
|
-
*
|
|
5
|
-
* This is the public entrypoint (LIB-003). Modules under `config/`, `core/`,
|
|
6
|
-
* `engine/`, `react/`, and `diagnostics/` are private; import them only through
|
|
7
|
-
* this file. The fake engine lives behind `@chipmobilesdk/rn-ads/testing` so
|
|
8
|
-
* test doubles cannot reach a production bundle.
|
|
9
|
-
*
|
|
10
|
-
* Nothing exported here names Google, AdMob, or any provider type (FR-002).
|
|
11
|
-
* `src/__tests__/public-api.test.ts` asserts that mechanically.
|
|
12
|
-
*
|
|
13
|
-
* The package owns capability: a safe, consistent way to request and present
|
|
14
|
-
* ads. The consuming app owns policy — where ads appear, when, how often, under
|
|
15
|
-
* what consent, and whether they appear at all. There is no placement rule, no
|
|
16
|
-
* frequency cap, and no screen name in this package (FR-045).
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// Configuration and state
|
|
20
|
-
export type {
|
|
21
|
-
AdContentRating,
|
|
22
|
-
AdFormat,
|
|
23
|
-
AdsConfig,
|
|
24
|
-
ConsentSnapshot,
|
|
25
|
-
ConsentState,
|
|
26
|
-
ConsentTestingOptions,
|
|
27
|
-
Enablement,
|
|
28
|
-
Environment,
|
|
29
|
-
FullScreenFormat,
|
|
30
|
-
InitStatus,
|
|
31
|
-
PlacementDefinition,
|
|
32
|
-
PlacementState,
|
|
33
|
-
PrivacyBlockReason,
|
|
34
|
-
PrivacyOptions,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
export
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
export {
|
|
89
|
-
export type {
|
|
90
|
-
export {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
export
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @chipmobilesdk/rn-ads — reusable advertising capability for
|
|
3
|
+
* ChipMobileSdk-family React Native apps.
|
|
4
|
+
*
|
|
5
|
+
* This is the public entrypoint (LIB-003). Modules under `config/`, `core/`,
|
|
6
|
+
* `engine/`, `react/`, and `diagnostics/` are private; import them only through
|
|
7
|
+
* this file. The fake engine lives behind `@chipmobilesdk/rn-ads/testing` so
|
|
8
|
+
* test doubles cannot reach a production bundle.
|
|
9
|
+
*
|
|
10
|
+
* Nothing exported here names Google, AdMob, or any provider type (FR-002).
|
|
11
|
+
* `src/__tests__/public-api.test.ts` asserts that mechanically.
|
|
12
|
+
*
|
|
13
|
+
* The package owns capability: a safe, consistent way to request and present
|
|
14
|
+
* ads. The consuming app owns policy — where ads appear, when, how often, under
|
|
15
|
+
* what consent, and whether they appear at all. There is no placement rule, no
|
|
16
|
+
* frequency cap, and no screen name in this package (FR-045).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// Configuration and state
|
|
20
|
+
export type {
|
|
21
|
+
AdContentRating,
|
|
22
|
+
AdFormat,
|
|
23
|
+
AdsConfig,
|
|
24
|
+
ConsentSnapshot,
|
|
25
|
+
ConsentState,
|
|
26
|
+
ConsentTestingOptions,
|
|
27
|
+
Enablement,
|
|
28
|
+
Environment,
|
|
29
|
+
FullScreenFormat,
|
|
30
|
+
InitStatus,
|
|
31
|
+
PlacementDefinition,
|
|
32
|
+
PlacementState,
|
|
33
|
+
PrivacyBlockReason,
|
|
34
|
+
PrivacyOptions,
|
|
35
|
+
PrivacyOptionsRequirement,
|
|
36
|
+
RetryPolicy,
|
|
37
|
+
Reward,
|
|
38
|
+
TimeoutConfig,
|
|
39
|
+
UnavailableReason,
|
|
40
|
+
Unsubscribe,
|
|
41
|
+
} from './config/types';
|
|
42
|
+
export { isFullScreenFormat } from './config/types';
|
|
43
|
+
|
|
44
|
+
// Timeout policy — exported so a consumer can read the defaults it is bound by
|
|
45
|
+
// rather than discovering them from a timeout in production (FR-032).
|
|
46
|
+
export {
|
|
47
|
+
AD_VALIDITY_BOUNDS,
|
|
48
|
+
APP_OPEN_VALIDITY_BOUNDS,
|
|
49
|
+
DEFAULT_AD_VALIDITY_MS,
|
|
50
|
+
DEFAULT_APP_OPEN_VALIDITY_MS,
|
|
51
|
+
DEFAULT_LOAD_TIMEOUT_MS,
|
|
52
|
+
DEFAULT_RETRY_POLICY,
|
|
53
|
+
DEFAULT_SHOW_TIMEOUT_MS,
|
|
54
|
+
DEFAULT_UNDECIDED_WARNING_MS,
|
|
55
|
+
LOAD_TIMEOUT_BOUNDS,
|
|
56
|
+
RETRY_BOUNDS,
|
|
57
|
+
SHOW_TIMEOUT_BOUNDS,
|
|
58
|
+
UNDECIDED_WARNING_BOUNDS,
|
|
59
|
+
} from './core/timers';
|
|
60
|
+
|
|
61
|
+
// Request throttle — account safety, added in 0.3.0 (FR-140). Exported so an app
|
|
62
|
+
// can read the floor it is bound by, and so the format-aware default is legible
|
|
63
|
+
// rather than something to discover from a `throttled` state in production.
|
|
64
|
+
export {
|
|
65
|
+
DEFAULT_BANNER_MIN_REQUEST_INTERVAL_MS,
|
|
66
|
+
DEFAULT_FULL_SCREEN_MIN_REQUEST_INTERVAL_MS,
|
|
67
|
+
MIN_REQUEST_INTERVAL_BOUNDS,
|
|
68
|
+
defaultMinRequestIntervalMs,
|
|
69
|
+
} from './core/requestThrottle';
|
|
70
|
+
|
|
71
|
+
// Enablement. `EnablementResult` is what `setEnabled` returns in place of
|
|
72
|
+
// 0.1.0's `void` — the defect that let a re-enable fail in silence (FR-122).
|
|
73
|
+
export type { EnablementResult } from './core/enablement';
|
|
74
|
+
|
|
75
|
+
// Instance, lifecycle, and results
|
|
76
|
+
export { createAds } from './core/adsInstance';
|
|
77
|
+
export type {
|
|
78
|
+
AdsInstance,
|
|
79
|
+
ConsentApi,
|
|
80
|
+
InitResult,
|
|
81
|
+
LoadResult,
|
|
82
|
+
PrivacyOptionsFormResult,
|
|
83
|
+
PrivacyUpdateResult,
|
|
84
|
+
ShowResult,
|
|
85
|
+
} from './core/adsInstance';
|
|
86
|
+
|
|
87
|
+
// React surface
|
|
88
|
+
export { AdsBanner } from './react/AdsBanner';
|
|
89
|
+
export type { AdsBannerProps } from './react/AdsBanner';
|
|
90
|
+
export { AdsProvider, useAds } from './react/AdsProvider';
|
|
91
|
+
export type { AdsProviderProps } from './react/AdsProvider';
|
|
92
|
+
export { useAdsEvents, useAdsStatus, usePlacementState } from './react/hooks';
|
|
93
|
+
|
|
94
|
+
// Diagnostics
|
|
95
|
+
export { AdsConfigError, AdsError, isAdsError } from './diagnostics/errors';
|
|
96
|
+
export type { AdsErrorCode, AdsOperation } from './diagnostics/errors';
|
|
97
|
+
export type {
|
|
98
|
+
AdEvent,
|
|
99
|
+
AdEventListener,
|
|
100
|
+
AdEventType,
|
|
101
|
+
ConfigWarning,
|
|
102
|
+
ImpressionSource,
|
|
103
|
+
} from './diagnostics/events';
|