@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 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
+ ```
@@ -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 };
@@ -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 };