@halo-ads/core 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.
- package/README.md +59 -0
- package/dist/index.d.mts +178 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.js +1079 -0
- package/dist/index.mjs +1042 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @halo-ads/core
|
|
2
|
+
|
|
3
|
+
> Framework-agnostic Halo Ads SDK core — ad fetching, DOM rendering, event tracking, and user profiling.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @halo-ads/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Key exports
|
|
12
|
+
|
|
13
|
+
| Export | Description |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `HaloAds` | Main singleton — `init`, `getAd`, `render`, `track`, `getProfile` |
|
|
16
|
+
| `AdClient` | Raw HTTP client for `/v1/decide` |
|
|
17
|
+
| `AdLoader` | Slot-based ad loading with fill/no-fill logic |
|
|
18
|
+
| `Analytics` | Event batching & flush |
|
|
19
|
+
| `EventTracker` | Impression / click tracking |
|
|
20
|
+
| `DOMRenderer` | Renders ad HTML into a container |
|
|
21
|
+
| `Recommendation` | Client-side ad scoring (context affinity) |
|
|
22
|
+
| `ProfileStore` | Persists user profile to `localStorage` |
|
|
23
|
+
| `MockAdProvider` / `MOCK_ADS` | Drop-in mock for testing without an API |
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { HaloAds, MockAdProvider } from '@halo-ads/core';
|
|
29
|
+
|
|
30
|
+
// Use real API
|
|
31
|
+
HaloAds.init({ publisherId: 'pub_xxx', apiKey: 'pk_live_...' });
|
|
32
|
+
|
|
33
|
+
// Or use mock for local dev / testing
|
|
34
|
+
HaloAds.init({ publisherId: 'pub_test' });
|
|
35
|
+
// (core auto-selects MockAdProvider in development when no apiKey is set)
|
|
36
|
+
|
|
37
|
+
const ad = await HaloAds.getAd({ slot: 'sl_banner', format: 'banner' });
|
|
38
|
+
|
|
39
|
+
await HaloAds.render({
|
|
40
|
+
container: '#ad-slot',
|
|
41
|
+
slot: 'sl_banner',
|
|
42
|
+
format: 'banner',
|
|
43
|
+
onImpression: (ad) => console.log('seen:', ad.id),
|
|
44
|
+
onClick: (ad) => console.log('clicked:', ad.id),
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Architecture
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
HaloAds (singleton)
|
|
52
|
+
├── AdClient → POST /v1/decide
|
|
53
|
+
├── AdLoader → manages slot state, fill/no-fill, caching
|
|
54
|
+
├── Analytics → batches TrackEvents, flushes on interval/unload
|
|
55
|
+
├── EventTracker → wraps Analytics with impression/click helpers
|
|
56
|
+
├── DOMRenderer → injects ad HTML, handles theme tokens
|
|
57
|
+
├── Recommendation → scores ads client-side against context_vector
|
|
58
|
+
└── ProfileStore → read/write UserProfile in localStorage
|
|
59
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { IAnalyticsProvider, HaloConfig, TrackEventName, TrackEventPayload, AnalyticsEvent, IProfileStore, UserProfile, Ad, HaloAdsInstance, AdRequest, RenderOptions, IAdProvider, AdResponse } from '@halo-ads/types';
|
|
2
|
+
export { Ad, AdCategory, AdFormat, AdRequest, AdResponse, AdTheme, AnalyticsEvent, HaloAdsInstance, HaloConfig, IAdProvider, IAnalyticsProvider, IProfileStore, RenderOptions, TrackEventName, TrackEventPayload, UserProfile } from '@halo-ads/types';
|
|
3
|
+
|
|
4
|
+
declare class Analytics {
|
|
5
|
+
private config;
|
|
6
|
+
private sessionId;
|
|
7
|
+
private provider;
|
|
8
|
+
constructor(provider?: IAnalyticsProvider);
|
|
9
|
+
configure(config: HaloConfig, sessionId: string): void;
|
|
10
|
+
track(name: TrackEventName, payload?: TrackEventPayload): void;
|
|
11
|
+
}
|
|
12
|
+
declare class ConsoleAnalyticsProvider implements IAnalyticsProvider {
|
|
13
|
+
send(event: AnalyticsEvent): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare class ProfileStore implements IProfileStore {
|
|
17
|
+
private profile;
|
|
18
|
+
private storageAvailable;
|
|
19
|
+
constructor();
|
|
20
|
+
private load;
|
|
21
|
+
private save;
|
|
22
|
+
get(): UserProfile;
|
|
23
|
+
update(partial: Partial<UserProfile>): void;
|
|
24
|
+
/** Add an ad ID to the seen list (for frequency capping) */
|
|
25
|
+
markAdSeen(adId: string): void;
|
|
26
|
+
/** Add an interest if not already present */
|
|
27
|
+
addInterest(interest: string): void;
|
|
28
|
+
clear(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare class EventTracker {
|
|
32
|
+
private analytics;
|
|
33
|
+
private profileStore;
|
|
34
|
+
private trackedImpressions;
|
|
35
|
+
private debug;
|
|
36
|
+
constructor(analytics: Analytics, profileStore: ProfileStore, debug?: boolean);
|
|
37
|
+
trackImpression(ad: Ad, slot: string): void;
|
|
38
|
+
trackClick(ad: Ad, slot: string): void;
|
|
39
|
+
trackView(ad: Ad, slot: string): void;
|
|
40
|
+
/** Set up IntersectionObserver to auto-track impressions */
|
|
41
|
+
observeElement(element: HTMLElement, ad: Ad, slot: string): () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare class HaloAdsSDK implements HaloAdsInstance {
|
|
45
|
+
private config;
|
|
46
|
+
private profileStore;
|
|
47
|
+
private analytics;
|
|
48
|
+
private tracker;
|
|
49
|
+
private client;
|
|
50
|
+
private loader;
|
|
51
|
+
private renderer;
|
|
52
|
+
private recommendation;
|
|
53
|
+
/**
|
|
54
|
+
* Initialize the Halo Ads SDK.
|
|
55
|
+
* Must be called before any other methods.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* HaloAds.init({
|
|
59
|
+
* publisherId: "pub_001",
|
|
60
|
+
* apiKey: "pk_test_...",
|
|
61
|
+
* debug: true
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
64
|
+
init(config: HaloConfig): void;
|
|
65
|
+
/**
|
|
66
|
+
* Track an analytics event.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* HaloAds.track("page_view")
|
|
70
|
+
* HaloAds.track("click", { adId: "ad_001" })
|
|
71
|
+
* HaloAds.track("purchase", { value: 49.99 })
|
|
72
|
+
*/
|
|
73
|
+
track(name: TrackEventName, payload?: TrackEventPayload): void;
|
|
74
|
+
/**
|
|
75
|
+
* Fetch an ad for a slot.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const ad = await HaloAds.getAd({ slot: "hero" })
|
|
79
|
+
*/
|
|
80
|
+
getAd(request: AdRequest): Promise<Ad | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Render an ad into a DOM container.
|
|
83
|
+
* Works like Google Adsense — just point at a container.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* HaloAds.render({ container: "#banner", slot: "hero" })
|
|
87
|
+
*/
|
|
88
|
+
render(options: RenderOptions): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Get the current user profile.
|
|
91
|
+
*/
|
|
92
|
+
getProfile(): UserProfile;
|
|
93
|
+
/**
|
|
94
|
+
* Get recommended ads based on user profile.
|
|
95
|
+
*/
|
|
96
|
+
getRecommended(limit?: number): Ad[];
|
|
97
|
+
/**
|
|
98
|
+
* Whether the SDK has been initialized.
|
|
99
|
+
*/
|
|
100
|
+
isInitialized(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Destroy the SDK instance (useful for testing / cleanup).
|
|
103
|
+
*/
|
|
104
|
+
destroy(): void;
|
|
105
|
+
/** @internal */
|
|
106
|
+
_getTracker(): EventTracker;
|
|
107
|
+
/** @internal */
|
|
108
|
+
_getProfileStore(): ProfileStore;
|
|
109
|
+
private assertInitialized;
|
|
110
|
+
}
|
|
111
|
+
declare const HaloAds: HaloAdsSDK;
|
|
112
|
+
|
|
113
|
+
declare class AdClient {
|
|
114
|
+
private provider;
|
|
115
|
+
private publisherId;
|
|
116
|
+
private debug;
|
|
117
|
+
constructor(provider: IAdProvider, publisherId: string, debug?: boolean);
|
|
118
|
+
fetchAd(slot: string, options?: Partial<AdRequest>): Promise<Ad | null>;
|
|
119
|
+
fetchMultiple(slots: string[], options?: Partial<AdRequest>): Promise<Record<string, Ad | null>>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
declare class AdLoader {
|
|
123
|
+
private client;
|
|
124
|
+
private cache;
|
|
125
|
+
private debug;
|
|
126
|
+
private loading;
|
|
127
|
+
constructor(client: AdClient, debug?: boolean);
|
|
128
|
+
private isCacheValid;
|
|
129
|
+
private getCategoryHint;
|
|
130
|
+
load(slot: string, options?: Partial<AdRequest>): Promise<Ad | null>;
|
|
131
|
+
/** Clear cache for a slot (force refresh on next load) */
|
|
132
|
+
invalidate(slot?: string): void;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
declare class Recommendation {
|
|
136
|
+
/**
|
|
137
|
+
* Rank ads by user interest score.
|
|
138
|
+
* Categories matching user interests are scored higher.
|
|
139
|
+
* Future: embed-based cosine similarity against interest vectors.
|
|
140
|
+
*/
|
|
141
|
+
rankAds(ads: Ad[], profile: UserProfile): Ad[];
|
|
142
|
+
/**
|
|
143
|
+
* Get recommended ads for a user.
|
|
144
|
+
* Returns ranked list excluding recently seen (if possible).
|
|
145
|
+
*/
|
|
146
|
+
getRecommended(profile: UserProfile, limit?: number): Ad[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare class DOMRenderer {
|
|
150
|
+
private tracker;
|
|
151
|
+
private debug;
|
|
152
|
+
private activeCount;
|
|
153
|
+
private timers;
|
|
154
|
+
constructor(tracker: EventTracker, debug?: boolean);
|
|
155
|
+
private resolveContainer;
|
|
156
|
+
private closePopup;
|
|
157
|
+
render(ad: Ad, options: RenderOptions): Promise<void>;
|
|
158
|
+
clear(container: string | HTMLElement): void;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
declare const MOCK_ADS: Ad[];
|
|
162
|
+
declare class MockAdProvider implements IAdProvider {
|
|
163
|
+
private ads;
|
|
164
|
+
/**
|
|
165
|
+
* Simulate network latency for a realistic dev experience.
|
|
166
|
+
*/
|
|
167
|
+
private delay;
|
|
168
|
+
/**
|
|
169
|
+
* Pick an ad for a given request. In a real implementation this
|
|
170
|
+
* would call POST /v1/decide with targeting parameters.
|
|
171
|
+
*/
|
|
172
|
+
fetchAd(request: AdRequest): Promise<AdResponse>;
|
|
173
|
+
fetchAds(requests: AdRequest[]): Promise<AdResponse[]>;
|
|
174
|
+
/** Exposed for testing / preview */
|
|
175
|
+
getAllAds(): Ad[];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { AdClient, AdLoader, Analytics, ConsoleAnalyticsProvider, DOMRenderer, EventTracker, HaloAds, MOCK_ADS, MockAdProvider, ProfileStore, Recommendation };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { IAnalyticsProvider, HaloConfig, TrackEventName, TrackEventPayload, AnalyticsEvent, IProfileStore, UserProfile, Ad, HaloAdsInstance, AdRequest, RenderOptions, IAdProvider, AdResponse } from '@halo-ads/types';
|
|
2
|
+
export { Ad, AdCategory, AdFormat, AdRequest, AdResponse, AdTheme, AnalyticsEvent, HaloAdsInstance, HaloConfig, IAdProvider, IAnalyticsProvider, IProfileStore, RenderOptions, TrackEventName, TrackEventPayload, UserProfile } from '@halo-ads/types';
|
|
3
|
+
|
|
4
|
+
declare class Analytics {
|
|
5
|
+
private config;
|
|
6
|
+
private sessionId;
|
|
7
|
+
private provider;
|
|
8
|
+
constructor(provider?: IAnalyticsProvider);
|
|
9
|
+
configure(config: HaloConfig, sessionId: string): void;
|
|
10
|
+
track(name: TrackEventName, payload?: TrackEventPayload): void;
|
|
11
|
+
}
|
|
12
|
+
declare class ConsoleAnalyticsProvider implements IAnalyticsProvider {
|
|
13
|
+
send(event: AnalyticsEvent): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare class ProfileStore implements IProfileStore {
|
|
17
|
+
private profile;
|
|
18
|
+
private storageAvailable;
|
|
19
|
+
constructor();
|
|
20
|
+
private load;
|
|
21
|
+
private save;
|
|
22
|
+
get(): UserProfile;
|
|
23
|
+
update(partial: Partial<UserProfile>): void;
|
|
24
|
+
/** Add an ad ID to the seen list (for frequency capping) */
|
|
25
|
+
markAdSeen(adId: string): void;
|
|
26
|
+
/** Add an interest if not already present */
|
|
27
|
+
addInterest(interest: string): void;
|
|
28
|
+
clear(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare class EventTracker {
|
|
32
|
+
private analytics;
|
|
33
|
+
private profileStore;
|
|
34
|
+
private trackedImpressions;
|
|
35
|
+
private debug;
|
|
36
|
+
constructor(analytics: Analytics, profileStore: ProfileStore, debug?: boolean);
|
|
37
|
+
trackImpression(ad: Ad, slot: string): void;
|
|
38
|
+
trackClick(ad: Ad, slot: string): void;
|
|
39
|
+
trackView(ad: Ad, slot: string): void;
|
|
40
|
+
/** Set up IntersectionObserver to auto-track impressions */
|
|
41
|
+
observeElement(element: HTMLElement, ad: Ad, slot: string): () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare class HaloAdsSDK implements HaloAdsInstance {
|
|
45
|
+
private config;
|
|
46
|
+
private profileStore;
|
|
47
|
+
private analytics;
|
|
48
|
+
private tracker;
|
|
49
|
+
private client;
|
|
50
|
+
private loader;
|
|
51
|
+
private renderer;
|
|
52
|
+
private recommendation;
|
|
53
|
+
/**
|
|
54
|
+
* Initialize the Halo Ads SDK.
|
|
55
|
+
* Must be called before any other methods.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* HaloAds.init({
|
|
59
|
+
* publisherId: "pub_001",
|
|
60
|
+
* apiKey: "pk_test_...",
|
|
61
|
+
* debug: true
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
64
|
+
init(config: HaloConfig): void;
|
|
65
|
+
/**
|
|
66
|
+
* Track an analytics event.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* HaloAds.track("page_view")
|
|
70
|
+
* HaloAds.track("click", { adId: "ad_001" })
|
|
71
|
+
* HaloAds.track("purchase", { value: 49.99 })
|
|
72
|
+
*/
|
|
73
|
+
track(name: TrackEventName, payload?: TrackEventPayload): void;
|
|
74
|
+
/**
|
|
75
|
+
* Fetch an ad for a slot.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const ad = await HaloAds.getAd({ slot: "hero" })
|
|
79
|
+
*/
|
|
80
|
+
getAd(request: AdRequest): Promise<Ad | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Render an ad into a DOM container.
|
|
83
|
+
* Works like Google Adsense — just point at a container.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* HaloAds.render({ container: "#banner", slot: "hero" })
|
|
87
|
+
*/
|
|
88
|
+
render(options: RenderOptions): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Get the current user profile.
|
|
91
|
+
*/
|
|
92
|
+
getProfile(): UserProfile;
|
|
93
|
+
/**
|
|
94
|
+
* Get recommended ads based on user profile.
|
|
95
|
+
*/
|
|
96
|
+
getRecommended(limit?: number): Ad[];
|
|
97
|
+
/**
|
|
98
|
+
* Whether the SDK has been initialized.
|
|
99
|
+
*/
|
|
100
|
+
isInitialized(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Destroy the SDK instance (useful for testing / cleanup).
|
|
103
|
+
*/
|
|
104
|
+
destroy(): void;
|
|
105
|
+
/** @internal */
|
|
106
|
+
_getTracker(): EventTracker;
|
|
107
|
+
/** @internal */
|
|
108
|
+
_getProfileStore(): ProfileStore;
|
|
109
|
+
private assertInitialized;
|
|
110
|
+
}
|
|
111
|
+
declare const HaloAds: HaloAdsSDK;
|
|
112
|
+
|
|
113
|
+
declare class AdClient {
|
|
114
|
+
private provider;
|
|
115
|
+
private publisherId;
|
|
116
|
+
private debug;
|
|
117
|
+
constructor(provider: IAdProvider, publisherId: string, debug?: boolean);
|
|
118
|
+
fetchAd(slot: string, options?: Partial<AdRequest>): Promise<Ad | null>;
|
|
119
|
+
fetchMultiple(slots: string[], options?: Partial<AdRequest>): Promise<Record<string, Ad | null>>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
declare class AdLoader {
|
|
123
|
+
private client;
|
|
124
|
+
private cache;
|
|
125
|
+
private debug;
|
|
126
|
+
private loading;
|
|
127
|
+
constructor(client: AdClient, debug?: boolean);
|
|
128
|
+
private isCacheValid;
|
|
129
|
+
private getCategoryHint;
|
|
130
|
+
load(slot: string, options?: Partial<AdRequest>): Promise<Ad | null>;
|
|
131
|
+
/** Clear cache for a slot (force refresh on next load) */
|
|
132
|
+
invalidate(slot?: string): void;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
declare class Recommendation {
|
|
136
|
+
/**
|
|
137
|
+
* Rank ads by user interest score.
|
|
138
|
+
* Categories matching user interests are scored higher.
|
|
139
|
+
* Future: embed-based cosine similarity against interest vectors.
|
|
140
|
+
*/
|
|
141
|
+
rankAds(ads: Ad[], profile: UserProfile): Ad[];
|
|
142
|
+
/**
|
|
143
|
+
* Get recommended ads for a user.
|
|
144
|
+
* Returns ranked list excluding recently seen (if possible).
|
|
145
|
+
*/
|
|
146
|
+
getRecommended(profile: UserProfile, limit?: number): Ad[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
declare class DOMRenderer {
|
|
150
|
+
private tracker;
|
|
151
|
+
private debug;
|
|
152
|
+
private activeCount;
|
|
153
|
+
private timers;
|
|
154
|
+
constructor(tracker: EventTracker, debug?: boolean);
|
|
155
|
+
private resolveContainer;
|
|
156
|
+
private closePopup;
|
|
157
|
+
render(ad: Ad, options: RenderOptions): Promise<void>;
|
|
158
|
+
clear(container: string | HTMLElement): void;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
declare const MOCK_ADS: Ad[];
|
|
162
|
+
declare class MockAdProvider implements IAdProvider {
|
|
163
|
+
private ads;
|
|
164
|
+
/**
|
|
165
|
+
* Simulate network latency for a realistic dev experience.
|
|
166
|
+
*/
|
|
167
|
+
private delay;
|
|
168
|
+
/**
|
|
169
|
+
* Pick an ad for a given request. In a real implementation this
|
|
170
|
+
* would call POST /v1/decide with targeting parameters.
|
|
171
|
+
*/
|
|
172
|
+
fetchAd(request: AdRequest): Promise<AdResponse>;
|
|
173
|
+
fetchAds(requests: AdRequest[]): Promise<AdResponse[]>;
|
|
174
|
+
/** Exposed for testing / preview */
|
|
175
|
+
getAllAds(): Ad[];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { AdClient, AdLoader, Analytics, ConsoleAnalyticsProvider, DOMRenderer, EventTracker, HaloAds, MOCK_ADS, MockAdProvider, ProfileStore, Recommendation };
|