universal-ad-loader 0.0.0-stage → 0.1.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.
@@ -0,0 +1,281 @@
1
+ // Tipi di UAL (Universal Ad Loader). Scritti a mano: la validazione vera resta lo schema JSON
2
+ // (schema/ual-config.schema.json); un test verifica che gli esempi passino entrambi.
3
+
4
+ export type Size = [width: number, height: number];
5
+ export type Device = 'desktop' | 'tablet' | 'mobile';
6
+
7
+ // ---------- configurazione ----------
8
+
9
+ export interface ConsentConfig {
10
+ /** `tcf` legge la CMP del sito; `none` = consenso non necessario. */
11
+ mode?: 'tcf' | 'none';
12
+ /** Attesa massima della scelta dell'utente (ms). Default 4000. */
13
+ timeoutMs?: number;
14
+ /** Attesa massima che la CMP compaia (ms). Default 1500. */
15
+ cmpWaitMs?: number;
16
+ /** Per quanto continuare a cercare una CMP che arriva in ritardo (ms). Default 30000. */
17
+ lateWatchMs?: number;
18
+ /** Purpose TCF necessarie perché il consenso sia "concesso". Default [1]. */
19
+ requiredPurposes?: number[];
20
+ /** ID del tuo ad server nella GVL IAB, se registrato. */
21
+ vendorId?: number;
22
+ }
23
+
24
+ export interface LazyConfig {
25
+ enabled?: boolean;
26
+ /** Distanza di anticipo, es. "200px". */
27
+ fetchMargin?: `${number}px` | `${number}%`;
28
+ }
29
+
30
+ export interface ViewabilityConfig {
31
+ /** Quota di pixel visibili (0–1). Default 0.5 (MRC). */
32
+ threshold?: number;
33
+ /** Durata continua (ms). Default 1000 (MRC). */
34
+ durationMs?: number;
35
+ }
36
+
37
+ export type TargetingValue = string | number | boolean | Array<string | number>;
38
+ export type Targeting = Record<string, TargetingValue>;
39
+
40
+ /** `optional`: attende la CMP. `required`: salta se manca il consenso. `contextual`: non attende la CMP. */
41
+ export type ProviderConsent = 'optional' | 'required' | 'contextual';
42
+
43
+ interface ProviderBase {
44
+ consent?: ProviderConsent;
45
+ /** Timeout del provider (ms); vuoto = `providerTimeoutMs` del sito. */
46
+ timeoutMs?: number;
47
+ }
48
+
49
+ export interface JsonProvider extends ProviderBase {
50
+ adapter: 'json';
51
+ endpoint: string;
52
+ headers?: Record<string, string>;
53
+ withCredentials?: boolean;
54
+ /** Nome di una funzione globale che adatta la risposta del server al formato UAL. */
55
+ map?: string;
56
+ }
57
+
58
+ export interface IframeProvider extends ProviderBase {
59
+ adapter: 'iframe';
60
+ /** URL del banner. Variabili: {params.x} {width} {height} {site} {slot} {device} {cb} {page.url} {page.ref} {consent.tcString} */
61
+ url: string;
62
+ sandbox?: string;
63
+ }
64
+
65
+ export interface ReviveProvider extends ProviderBase {
66
+ adapter: 'revive';
67
+ server: string;
68
+ deliveryPath?: string;
69
+ }
70
+
71
+ export interface ReviveAsyncProvider extends ProviderBase {
72
+ adapter: 'revive-async';
73
+ server: string;
74
+ reviveId: string;
75
+ deliveryPath?: string;
76
+ fillTimeoutMs?: number;
77
+ }
78
+
79
+ export interface GptProvider extends ProviderBase {
80
+ adapter: 'gpt';
81
+ /** Template: {network} {site} {slot} {section} {params.x} */
82
+ adUnitPath: string;
83
+ network?: string;
84
+ singleRequest?: boolean;
85
+ nonPersonalizedWithoutConsent?: boolean;
86
+ src?: string;
87
+ fillTimeoutMs?: number;
88
+ }
89
+
90
+ export interface AdsenseProvider extends ProviderBase {
91
+ adapter: 'adsense';
92
+ client: `ca-pub-${number}`;
93
+ test?: boolean;
94
+ fillTimeoutMs?: number;
95
+ }
96
+
97
+ export type Creative = {
98
+ id?: string;
99
+ type?: 'image' | 'html';
100
+ alt?: string;
101
+ width: number;
102
+ height: number;
103
+ clickUrl?: string;
104
+ /** Più alto = più frequente. */
105
+ weight?: number;
106
+ /** Solo in questi slot (vuoto = tutti). */
107
+ slots?: string[];
108
+ devices?: Device[];
109
+ /** Date AAAA-MM-GG (la data "to" è inclusa). */
110
+ from?: string;
111
+ to?: string;
112
+ } & ({ src: string; html?: string } | { html: string; src?: string });
113
+
114
+ export interface HouseProvider extends ProviderBase {
115
+ adapter: 'house';
116
+ creatives: [Creative, ...Creative[]];
117
+ }
118
+
119
+ export type ProviderConfig =
120
+ | JsonProvider | IframeProvider | ReviveProvider | ReviveAsyncProvider
121
+ | GptProvider | AdsenseProvider | HouseProvider;
122
+
123
+ export interface SizeMapping {
124
+ /** Larghezza minima del viewport (px). Metti sempre una fascia con 0. */
125
+ minWidth: number;
126
+ sizes: Size[];
127
+ }
128
+
129
+ export type ProviderRef<P extends string = string> =
130
+ | P
131
+ | { id: P; params?: Record<string, unknown> };
132
+
133
+ export interface SlotConfig<P extends string = string> {
134
+ sizes?: Size[];
135
+ sizeMapping?: SizeMapping[];
136
+ /** Waterfall: i provider vengono provati in ordine. */
137
+ providers: [ProviderRef<P>, ...ProviderRef<P>[]];
138
+ label?: string;
139
+ minHeight?: number;
140
+ lazy?: boolean;
141
+ collapseEmpty?: boolean;
142
+ refreshSec?: number;
143
+ maxRefresh?: number;
144
+ enabled?: boolean;
145
+ viewability?: ViewabilityConfig;
146
+ }
147
+
148
+ export interface PageRule {
149
+ /** Espressione regolare sul percorso della pagina. */
150
+ match: string;
151
+ disable?: string[];
152
+ enable?: string[];
153
+ targeting?: Targeting;
154
+ slots?: Record<string, Partial<SlotConfig>>;
155
+ }
156
+
157
+ /**
158
+ * `P` = id dei provider definiti, `S` = id ammessi nei waterfall degli slot (di default gli stessi).
159
+ * `defineConfig` li separa per far segnalare un provider inesistente.
160
+ */
161
+ export interface UalConfig<P extends string = string, S extends string = P> {
162
+ /** ID del sito, inviato agli adapter. */
163
+ site: string;
164
+ debug?: boolean;
165
+ consent?: ConsentConfig;
166
+ lazy?: LazyConfig;
167
+ viewability?: ViewabilityConfig;
168
+ collapseEmpty?: boolean;
169
+ providerTimeoutMs?: number;
170
+ targeting?: Targeting;
171
+ providers: Record<P, ProviderConfig>;
172
+ slots: Record<string, SlotConfig<S>>;
173
+ pageRules?: PageRule[];
174
+ }
175
+
176
+ /**
177
+ * Identità tipizzata: dà completamento e controllo dei tipi, e segnala un provider inesistente
178
+ * nel waterfall di uno slot.
179
+ */
180
+ export function defineConfig<const P extends string>(config: UalConfig<P, NoInfer<P>>): UalConfig<P>;
181
+
182
+ // ---------- istanza ----------
183
+
184
+ export interface Consent {
185
+ gdprApplies?: boolean;
186
+ tcString: string;
187
+ purposes: Record<string, boolean>;
188
+ vendorConsents?: Record<string, boolean>;
189
+ granted: boolean;
190
+ /** `pending` finché la CMP non risponde; `no-cmp` e `timeout` = consenso non concesso. */
191
+ source: 'tcf' | 'none' | 'no-cmp' | 'timeout' | 'pending';
192
+ }
193
+
194
+ export interface SlotInfo {
195
+ slot: string;
196
+ id: string;
197
+ provider?: string;
198
+ status: string;
199
+ el: HTMLElement;
200
+ }
201
+
202
+ export interface UalEventMap {
203
+ ready: { site: string };
204
+ consent: Consent;
205
+ slotRegistered: SlotInfo;
206
+ slotRequested: { slot: string; id: string; provider: string };
207
+ slotRendered: SlotInfo & { width?: number; height?: number; meta?: unknown };
208
+ slotEmpty: SlotInfo;
209
+ slotViewable: SlotInfo;
210
+ slotClick: SlotInfo;
211
+ error: { provider?: string; slot?: string; error: Error };
212
+ }
213
+
214
+ export interface AdapterSlot {
215
+ id: string;
216
+ name: string;
217
+ /** Contenitore in cui un adapter che rende da solo (`fill`) inserisce l'annuncio. */
218
+ el: HTMLElement;
219
+ sizes: Size[];
220
+ params: Record<string, any>;
221
+ }
222
+
223
+ export interface AdapterContext {
224
+ site: string;
225
+ page: { url: string; path: string; ref: string; title: string };
226
+ device: Device;
227
+ viewport: { w: number; h: number };
228
+ targeting: Targeting;
229
+ consent: Consent;
230
+ debug: boolean;
231
+ }
232
+
233
+ export interface AdResult {
234
+ type?: 'image' | 'html' | 'url';
235
+ src?: string;
236
+ html?: string;
237
+ url?: string;
238
+ width: number;
239
+ height: number;
240
+ clickUrl?: string;
241
+ trackers?: { impression?: string[]; viewable?: string[]; click?: string[] };
242
+ sandbox?: string;
243
+ }
244
+
245
+ /** Adapter personalizzato: o `request` (UAL rende l'annuncio) o `fill` (rende da solo in `slot.el`). */
246
+ export interface Adapter {
247
+ init?(providerConfig: any, ctx: AdapterContext): void | Promise<void>;
248
+ request?(slots: AdapterSlot[], providerConfig: any, ctx: AdapterContext): Promise<Record<string, AdResult | null>>;
249
+ fill?(slots: AdapterSlot[], providerConfig: any, ctx: AdapterContext): Promise<Record<string, { filled: boolean; width?: number; height?: number; meta?: unknown }>>;
250
+ destroy?(slot: { id: string; el: HTMLElement }, providerConfig: any): void;
251
+ }
252
+
253
+ export interface Ual {
254
+ readonly version: string;
255
+ /** Avvia UAL con una configurazione (oggetto) o l'URL del JSON. Una sola volta per istanza. */
256
+ init(source: UalConfig | string): Promise<void>;
257
+ isInitialized(): boolean;
258
+ /** Promessa dell'init avviato (null se mai avviato). */
259
+ whenReady(): Promise<void> | null;
260
+ on<K extends keyof UalEventMap>(event: K, handler: (data: UalEventMap[K], event: K) => void): () => void;
261
+ on(event: '*', handler: (data: any, event: string) => void): () => void;
262
+ off(event: string, handler: (...args: any[]) => void): void;
263
+ registerAdapter(name: string, adapter: Adapter): void;
264
+ /** Targeting key-value. Vale anche prima dell'init e dopo pageView(); `null` rimuove la chiave. */
265
+ setTargeting(targeting: Record<string, TargetingValue | null | undefined>): void;
266
+ /** Ricarica gli slot indicati (tutti se senza argomenti). */
267
+ refresh(names?: string[]): void;
268
+ /** Da chiamare a ogni cambio di pagina lato client: ricalcola regole per pagina e slot. */
269
+ pageView(): void;
270
+ getSlots(): SlotInfo[];
271
+ getConsent(): Consent;
272
+ debug(on: boolean): void;
273
+ }
274
+
275
+ export const version: string;
276
+
277
+ /** Nuova istanza, senza toccare window né document: sicuro da importare sul server. */
278
+ export function createUal(): Ual;
279
+
280
+ /** Istanza condivisa della pagina. Solo nel browser: sul server lancia un errore esplicito. */
281
+ export function getUal(): Ual;