@digia-engage/core 2.3.1 → 2.4.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/DigiaEngageReactNative.podspec +1 -1
- package/README.md +70 -0
- package/android/.project +28 -0
- package/android/build.gradle +1 -1
- package/android/local.properties +1 -0
- package/android/src/main/java/com/digia/engage/rn/DigiaModule.kt +64 -6
- package/ios/DigiaModule.swift +70 -8
- package/ios/RNEventBridgePlugin.swift +2 -0
- package/lib/commonjs/Digia.js +139 -100
- package/lib/commonjs/Digia.js.map +1 -1
- package/lib/commonjs/DigiaAnchorView.js +11 -1
- package/lib/commonjs/DigiaAnchorView.js.map +1 -1
- package/lib/commonjs/DigiaProvider.js +63 -2
- package/lib/commonjs/DigiaProvider.js.map +1 -1
- package/lib/commonjs/NativeDigiaEngage.js +3 -0
- package/lib/commonjs/NativeDigiaEngage.js.map +1 -1
- package/lib/commonjs/digiaAnchorRegistry.js +3 -1
- package/lib/commonjs/digiaAnchorRegistry.js.map +1 -1
- package/lib/commonjs/frequencyStore.js +3 -3
- package/lib/commonjs/frequencyStore.js.map +1 -1
- package/lib/commonjs/index.js +0 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/Digia.js +139 -100
- package/lib/module/Digia.js.map +1 -1
- package/lib/module/DigiaAnchorView.js +11 -1
- package/lib/module/DigiaAnchorView.js.map +1 -1
- package/lib/module/DigiaProvider.js +65 -3
- package/lib/module/DigiaProvider.js.map +1 -1
- package/lib/module/NativeDigiaEngage.js +3 -0
- package/lib/module/NativeDigiaEngage.js.map +1 -1
- package/lib/module/digiaAnchorRegistry.js +3 -1
- package/lib/module/digiaAnchorRegistry.js.map +1 -1
- package/lib/module/frequencyStore.js +3 -3
- package/lib/module/frequencyStore.js.map +1 -1
- package/lib/module/index.js +4 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/Digia.d.ts +17 -8
- package/lib/typescript/Digia.d.ts.map +1 -1
- package/lib/typescript/DigiaAnchorView.d.ts.map +1 -1
- package/lib/typescript/DigiaProvider.d.ts +3 -1
- package/lib/typescript/DigiaProvider.d.ts.map +1 -1
- package/lib/typescript/NativeDigiaEngage.d.ts +9 -0
- package/lib/typescript/NativeDigiaEngage.d.ts.map +1 -1
- package/lib/typescript/digiaAnchorRegistry.d.ts +1 -0
- package/lib/typescript/digiaAnchorRegistry.d.ts.map +1 -1
- package/lib/typescript/frequencyStore.d.ts +1 -1
- package/lib/typescript/frequencyStore.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +5 -5
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/templateTypes.d.ts +24 -1
- package/lib/typescript/templateTypes.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +17 -13
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +13 -14
- package/src/Digia.ts +142 -114
- package/src/DigiaAnchorView.tsx +6 -1
- package/src/DigiaProvider.tsx +76 -2
- package/src/NativeDigiaEngage.ts +20 -0
- package/src/digiaAnchorRegistry.ts +3 -1
- package/src/frequencyStore.ts +4 -4
- package/src/index.ts +5 -5
- package/src/templateTypes.ts +31 -1
- package/src/types.ts +17 -13
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The translation contract between a CEP plugin and Digia's rendering engine.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Plugin authors map their CEP's native callback into this struct.
|
|
5
|
+
* Mirrors CEPTriggerPayload on Android / Flutter — Digia core never imports
|
|
6
|
+
* CleverTap, MoEngage, or WebEngage types directly.
|
|
5
7
|
*/
|
|
6
|
-
export interface
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
/** CEP
|
|
12
|
-
|
|
8
|
+
export interface CEPTriggerPayload {
|
|
9
|
+
/** The CEP's own identifier for this campaign instance. Opaque to Digia — passed through for analytics correlation. */
|
|
10
|
+
cepCampaignId: string;
|
|
11
|
+
/** Additional metadata the CEP passes through (UTM params, user segment, CEP-specific tracking fields). Forwarded as-is in ExperienceEvents. */
|
|
12
|
+
cepMetadata: Record<string, unknown>;
|
|
13
|
+
/** The coupling key linking this CEP campaign to a Digia campaign. Used to look up the matching campaign in the store. */
|
|
14
|
+
campaignKey: string;
|
|
15
|
+
/** Optional runtime variables to interpolate into the campaign config. Keys must match variable placeholders in the Digia dashboard. */
|
|
16
|
+
variables?: Record<string, string>;
|
|
13
17
|
}
|
|
14
18
|
export type CampaignType = 'nudge' | 'guide' | 'inline' | 'survey';
|
|
15
19
|
/** The experience became visible to the user. */
|
|
@@ -98,7 +102,7 @@ export type GuideLifecycleEvent = {
|
|
|
98
102
|
*/
|
|
99
103
|
export interface DigiaDelegate {
|
|
100
104
|
/** Deliver a campaign payload into the Digia rendering engine. */
|
|
101
|
-
onCampaignTriggered(payload:
|
|
105
|
+
onCampaignTriggered(payload: CEPTriggerPayload): void | Promise<void>;
|
|
102
106
|
/** Invalidate / dismiss a campaign by its ID. */
|
|
103
107
|
onCampaignInvalidated(campaignId: string): void;
|
|
104
108
|
}
|
|
@@ -117,7 +121,7 @@ export interface DigiaPlugin {
|
|
|
117
121
|
* (impressed / clicked / dismissed). Plugins use this to report
|
|
118
122
|
* analytics back to their CEP platform.
|
|
119
123
|
*/
|
|
120
|
-
notifyEvent(event: DigiaExperienceEvent, payload:
|
|
124
|
+
notifyEvent(event: DigiaExperienceEvent, payload: CEPTriggerPayload): void;
|
|
121
125
|
/**
|
|
122
126
|
* Called by the Digia SDK to record a named analytics event with properties.
|
|
123
127
|
* Implement this to forward Digia lifecycle events (e.g. "Digia Experience Viewed")
|
|
@@ -193,8 +197,8 @@ export interface FrequencyEvalResult {
|
|
|
193
197
|
* Configuration for initialising the Digia Engage SDK.
|
|
194
198
|
*/
|
|
195
199
|
export interface DigiaConfig {
|
|
196
|
-
/** The Engage
|
|
197
|
-
|
|
200
|
+
/** The Engage API key — sent as x-digia-project-id on all SDK requests. */
|
|
201
|
+
apiKey: string;
|
|
198
202
|
/**
|
|
199
203
|
* Base URL for the Digia API.
|
|
200
204
|
* Defaults to the production API root, or the Engage sandbox root when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digia-engage/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "React Native bridge for Digia Engage – renders native Android Compose UI inside React Native apps",
|
|
5
|
-
"main": "
|
|
6
|
-
"module": "
|
|
7
|
-
"types": "
|
|
8
|
-
"react-native": "src/index
|
|
9
|
-
"source": "src/index
|
|
5
|
+
"main": "lib/commonjs/index",
|
|
6
|
+
"module": "lib/module/index",
|
|
7
|
+
"types": "lib/typescript/index.d.ts",
|
|
8
|
+
"react-native": "src/index",
|
|
9
|
+
"source": "src/index",
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
12
|
"lib",
|
|
@@ -45,18 +45,17 @@
|
|
|
45
45
|
"author": "Digia Technology Private Limited",
|
|
46
46
|
"license": "BUSL-1.1",
|
|
47
47
|
"dependencies": {
|
|
48
|
+
"@floating-ui/core": "^1.0.0",
|
|
48
49
|
"@react-native-async-storage/async-storage": "^2.1.2",
|
|
49
|
-
"react-native-
|
|
50
|
-
"
|
|
51
|
-
"@floating-ui/core": "^1.0.0"
|
|
50
|
+
"react-native-svg": "^15.15.5",
|
|
51
|
+
"react-native-uuid": "^2.0.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@react-native/eslint-config": "^0.
|
|
55
|
-
"@types/react": "^
|
|
56
|
-
"@types/react-native": "^0.73.0",
|
|
54
|
+
"@react-native/eslint-config": "^0.83.0",
|
|
55
|
+
"@types/react": "^19.0.0",
|
|
57
56
|
"eslint": "^8.51.0",
|
|
58
|
-
"react": "
|
|
59
|
-
"react-native": "0.
|
|
57
|
+
"react": "19.2.0",
|
|
58
|
+
"react-native": "0.83.0",
|
|
60
59
|
"react-native-builder-bob": "^0.23.0",
|
|
61
60
|
"typescript": "^5.2.0"
|
|
62
61
|
},
|
package/src/Digia.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* import { Digia } from '@digia/engage-react-native';
|
|
8
8
|
*
|
|
9
9
|
* // In your App entry point (e.g. App.tsx):
|
|
10
|
-
* await Digia.initialize({
|
|
10
|
+
* await Digia.initialize({ apiKey: 'YOUR_API_KEY' });
|
|
11
11
|
*
|
|
12
12
|
* // Whenever your navigation screen changes:
|
|
13
13
|
* Digia.setCurrentScreen('Home');
|
|
@@ -19,6 +19,7 @@ import { DeviceEventEmitter } from 'react-native';
|
|
|
19
19
|
import { nativeDigiaModule } from './NativeDigiaEngage';
|
|
20
20
|
import { digiaHealthReporter, HealthEventType } from './DigiaHealthReporter';
|
|
21
21
|
import { digiaGuideController } from './DigiaGuideController';
|
|
22
|
+
import { digiaAnchorRegistry } from './digiaAnchorRegistry';
|
|
22
23
|
import { parseVariableMap } from './interpolate';
|
|
23
24
|
import { digiaActionHandler } from './actionHandler';
|
|
24
25
|
import uuid from 'react-native-uuid';
|
|
@@ -26,6 +27,7 @@ import { frequencyStore } from './frequencyStore';
|
|
|
26
27
|
import { evaluate, hasPolicy, isSessionPolicy } from './frequencyEvaluator';
|
|
27
28
|
import type {
|
|
28
29
|
ActionContext,
|
|
30
|
+
CEPTriggerPayload,
|
|
29
31
|
CampaignType,
|
|
30
32
|
DigiaConfig,
|
|
31
33
|
DigiaDelegate,
|
|
@@ -34,7 +36,6 @@ import type {
|
|
|
34
36
|
FrequencyPolicy,
|
|
35
37
|
FrequencyState,
|
|
36
38
|
GuideLifecycleEvent,
|
|
37
|
-
InAppPayload,
|
|
38
39
|
} from './types';
|
|
39
40
|
import type { TemplateConfig } from './templateTypes';
|
|
40
41
|
|
|
@@ -56,11 +57,11 @@ class DigiaClass implements DigiaDelegate {
|
|
|
56
57
|
// Tracks whether the native bridge plugin (RNEventBridgePlugin) has been
|
|
57
58
|
// wired to the native SDK. Done once on the first Digia.register() call.
|
|
58
59
|
private _nativeBridgeWired = false;
|
|
59
|
-
// Cache of triggered payloads keyed by
|
|
60
|
-
// the full
|
|
61
|
-
private readonly _activePayloads = new Map<string,
|
|
60
|
+
// Cache of triggered payloads keyed by cepCampaignId, used to reconstruct
|
|
61
|
+
// the full CEPTriggerPayload when overlay lifecycle events arrive from native.
|
|
62
|
+
private readonly _activePayloads = new Map<string, CEPTriggerPayload>();
|
|
62
63
|
private _engageSubscription: { remove(): void } | null = null;
|
|
63
|
-
private
|
|
64
|
+
private _apiKey = '';
|
|
64
65
|
private _deviceId = '';
|
|
65
66
|
private _apiBaseUrl = '';
|
|
66
67
|
private _logLevel: DigiaConfig['logLevel'] = 'error';
|
|
@@ -78,11 +79,12 @@ class DigiaClass implements DigiaDelegate {
|
|
|
78
79
|
async initialize(config: DigiaConfig): Promise<void> {
|
|
79
80
|
const environment = config.environment ?? 'production';
|
|
80
81
|
const logLevel = config.logLevel ?? 'error';
|
|
81
|
-
this.
|
|
82
|
+
this._apiKey = config.apiKey;
|
|
82
83
|
this._apiBaseUrl = this._resolveApiBaseUrl(config);
|
|
83
84
|
this._logLevel = logLevel;
|
|
84
85
|
this._fontFamily = config.fontFamily?.trim() || undefined;
|
|
85
|
-
|
|
86
|
+
this._log(`Digia SDK initializing | apiKey=${config.apiKey.slice(0, 8)}… env=${environment}`);
|
|
87
|
+
digiaHealthReporter.init(config.apiKey, this._apiBaseUrl);
|
|
86
88
|
|
|
87
89
|
digiaActionHandler.configure({
|
|
88
90
|
onAction: config.onAction,
|
|
@@ -93,16 +95,16 @@ class DigiaClass implements DigiaDelegate {
|
|
|
93
95
|
});
|
|
94
96
|
|
|
95
97
|
try {
|
|
96
|
-
await nativeDigiaModule.initialize(config.
|
|
98
|
+
await nativeDigiaModule.initialize(config.apiKey, environment, logLevel, config.baseUrl, config.fontFamily);
|
|
97
99
|
} catch (e) {
|
|
98
|
-
|
|
99
|
-
// digiaHealthReporter.report(HealthEventType.fetch_failed, { error_code: 0, platform: 'react_native' });
|
|
100
|
+
this._error(`Digia SDK native init failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
100
101
|
throw e;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
this._deviceId = await this._loadOrCreateDeviceId();
|
|
104
|
-
await frequencyStore.
|
|
105
|
+
await frequencyStore.checkApiKey(config.apiKey);
|
|
105
106
|
await this._refreshCampaignStore();
|
|
107
|
+
this._log(`Digia SDK ready | campaigns=${this._campaignsByKey.size}`);
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
/**
|
|
@@ -116,13 +118,16 @@ class DigiaClass implements DigiaDelegate {
|
|
|
116
118
|
* ```ts
|
|
117
119
|
* import { DigiaMoEngagePlugin } from '@digia/moengage-plugin';
|
|
118
120
|
*
|
|
119
|
-
* await Digia.initialize({
|
|
121
|
+
* await Digia.initialize({ apiKey: 'YOUR_API_KEY' });
|
|
120
122
|
* Digia.register(new DigiaMoEngagePlugin({ moEngage: MoEngage }));
|
|
121
123
|
* ```
|
|
122
124
|
*/
|
|
123
125
|
register(plugin: DigiaPlugin): void {
|
|
124
126
|
if (this._plugins.has(plugin.identifier)) {
|
|
127
|
+
this._log(`Plugin replaced: ${plugin.identifier}`);
|
|
125
128
|
this._plugins.get(plugin.identifier)!.teardown();
|
|
129
|
+
} else {
|
|
130
|
+
this._log(`Plugin registered: ${plugin.identifier}`);
|
|
126
131
|
}
|
|
127
132
|
// Wire the native bridge plugin once, before the first plugin's setup()
|
|
128
133
|
// so the delegate is ready when JS campaigns start flowing.
|
|
@@ -154,6 +159,7 @@ class DigiaClass implements DigiaDelegate {
|
|
|
154
159
|
* All registered plugins will have forwardScreen() called automatically.
|
|
155
160
|
*/
|
|
156
161
|
setCurrentScreen(name: string): void {
|
|
162
|
+
this._log(`Screen: ${name}`);
|
|
157
163
|
this._currentScreen = name;
|
|
158
164
|
nativeDigiaModule.setCurrentScreen(name);
|
|
159
165
|
this._plugins.forEach((plugin) => plugin.forwardScreen(name));
|
|
@@ -169,6 +175,22 @@ class DigiaClass implements DigiaDelegate {
|
|
|
169
175
|
this._registeredAnchorKeys.delete(anchorKey);
|
|
170
176
|
}
|
|
171
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Associate a known user ID with subsequent analytics events.
|
|
180
|
+
* Call after login; rotates the analytics session automatically.
|
|
181
|
+
*/
|
|
182
|
+
setUserId(userId: string): void {
|
|
183
|
+
nativeDigiaModule.setUserId(userId);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Clear the user ID (e.g. on logout).
|
|
188
|
+
* Subsequent events are attributed to the anonymous ID and a new session.
|
|
189
|
+
*/
|
|
190
|
+
clearUserId(): void {
|
|
191
|
+
nativeDigiaModule.clearUserId();
|
|
192
|
+
}
|
|
193
|
+
|
|
172
194
|
/**
|
|
173
195
|
* Global font family configured via {@link initialize}, or `undefined` when
|
|
174
196
|
* none was set. Used by the JS-rendered guide overlays (tooltip/spotlight)
|
|
@@ -183,86 +205,101 @@ class DigiaClass implements DigiaDelegate {
|
|
|
183
205
|
// Mirrors DigiaCEPDelegate on Android.
|
|
184
206
|
// Forwards to the native DigiaCEPDelegate via the bridge.
|
|
185
207
|
|
|
186
|
-
async onCampaignTriggered(payload:
|
|
208
|
+
async onCampaignTriggered(payload: CEPTriggerPayload): Promise<void> {
|
|
187
209
|
if (!this._nativeBridgeWired) {
|
|
188
|
-
digiaHealthReporter.report(HealthEventType.plugin_not_registered, { campaign_key: payload.
|
|
210
|
+
digiaHealthReporter.report(HealthEventType.plugin_not_registered, { campaign_key: payload.campaignKey });
|
|
189
211
|
}
|
|
190
212
|
|
|
191
|
-
const campaignKey =
|
|
192
|
-
this._log(`onCampaignTriggered
|
|
213
|
+
const { cepCampaignId, campaignKey, variables, cepMetadata } = payload;
|
|
214
|
+
this._log(`onCampaignTriggered cepCampaignId=${cepCampaignId} campaignKey=${campaignKey} knownKeys=[${[...this._campaignsByKey.keys()].join(', ')}]`);
|
|
193
215
|
|
|
194
|
-
|
|
195
|
-
const campaign = this._campaignsByKey.get(campaignKey);
|
|
196
|
-
|
|
197
|
-
if (campaign && hasPolicy(campaign.frequency)) {
|
|
198
|
-
const policy = campaign.frequency!;
|
|
199
|
-
const isSession = isSessionPolicy(policy);
|
|
200
|
-
const state = await this._getFrequencyState(campaignKey, isSession);
|
|
201
|
-
const result = evaluate(policy, state, Date.now());
|
|
202
|
-
if (!result.allow) {
|
|
203
|
-
this._log(`frequency_capped campaign_key=${campaignKey} reason=${result.reason}`);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
216
|
+
const campaign = this._campaignsByKey.get(campaignKey);
|
|
207
217
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
if (campaign && hasPolicy(campaign.frequency)) {
|
|
219
|
+
const policy = campaign.frequency!;
|
|
220
|
+
const isSession = isSessionPolicy(policy);
|
|
221
|
+
const state = await this._getFrequencyState(campaignKey, isSession);
|
|
222
|
+
const result = evaluate(policy, state, Date.now());
|
|
223
|
+
if (!result.allow) {
|
|
224
|
+
this._log(`frequency_capped campaign_key=${campaignKey} reason=${result.reason}`);
|
|
215
225
|
return;
|
|
216
226
|
}
|
|
227
|
+
}
|
|
217
228
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
!config ||
|
|
222
|
-
(config.templateType !== 'tooltip' && config.templateType !== 'spotlight') ||
|
|
223
|
-
config.steps.length === 0
|
|
224
|
-
) {
|
|
225
|
-
digiaHealthReporter.report(HealthEventType.anchor_not_on_screen, {
|
|
226
|
-
campaign_key: campaignKey,
|
|
227
|
-
reason: 'guide_campaign_has_no_steps',
|
|
228
|
-
});
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
229
|
+
// Synthesise the content map expected by the native bridge.
|
|
230
|
+
const bridgeContent: Record<string, unknown> = { digia_campaign_key: campaignKey };
|
|
231
|
+
if (variables) bridgeContent.variables = variables;
|
|
231
232
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
});
|
|
233
|
+
if (campaign?.campaign_type === 'inline' || campaign?.campaign_type === 'survey') {
|
|
234
|
+
this._log(`${campaign.campaign_type} campaign triggered campaign_key=${campaignKey}, forwarding to native`);
|
|
235
|
+
this._activePayloads.set(cepCampaignId, payload);
|
|
236
|
+
if (campaign.campaign_type === 'inline') {
|
|
237
|
+
this._emitSlotWidth(campaign);
|
|
238
|
+
}
|
|
239
|
+
nativeDigiaModule.triggerCampaign(cepCampaignId, bridgeContent, cepMetadata);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
if (campaign?.campaign_type === 'guide') {
|
|
244
|
+
const config = this._parseTemplateConfig(campaign);
|
|
245
|
+
if (
|
|
246
|
+
!config ||
|
|
247
|
+
(config.templateType !== 'tooltip' && config.templateType !== 'spotlight') ||
|
|
248
|
+
config.steps.length === 0
|
|
249
|
+
) {
|
|
250
|
+
digiaHealthReporter.report(HealthEventType.anchor_not_on_screen, {
|
|
251
|
+
campaign_key: campaignKey,
|
|
252
|
+
reason: 'guide_campaign_has_no_steps',
|
|
253
|
+
});
|
|
250
254
|
return;
|
|
251
255
|
}
|
|
252
256
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
const firstAnchorKey = config.steps[0].anchorKey;
|
|
258
|
+
if (!digiaAnchorRegistry.isRegistered(firstAnchorKey)) {
|
|
259
|
+
// eslint-disable-next-line no-console
|
|
260
|
+
console.warn(`[Digia] campaign dropped — anchor_key "${firstAnchorKey}" is not registered on this screen (campaign_key=${campaignKey})`);
|
|
261
|
+
digiaHealthReporter.report(HealthEventType.anchor_not_on_screen, {
|
|
256
262
|
campaign_key: campaignKey,
|
|
257
|
-
|
|
258
|
-
|
|
263
|
+
reason: 'anchor_key_not_registered',
|
|
264
|
+
anchor_key: firstAnchorKey,
|
|
259
265
|
});
|
|
260
266
|
return;
|
|
261
267
|
}
|
|
268
|
+
|
|
269
|
+
this._activePayloads.set(cepCampaignId, payload);
|
|
270
|
+
const digiaId = campaign._id ?? campaign.id ?? campaignKey;
|
|
271
|
+
const mounted = digiaGuideController.start({
|
|
272
|
+
payloadId: cepCampaignId,
|
|
273
|
+
campaignKey,
|
|
274
|
+
campaignId: digiaId,
|
|
275
|
+
variables,
|
|
276
|
+
config,
|
|
277
|
+
onExperienceEvent: (event) => this._onGuideLifecycleEvent(event, cepCampaignId, campaignKey, digiaId),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
this._log(`guide trigger campaign_key=${campaignKey} mounted=${mounted}`);
|
|
281
|
+
if (!mounted) {
|
|
282
|
+
this._log(`event controller failed to mount guide campaign_key=${campaignKey}`);
|
|
283
|
+
digiaHealthReporter.report(HealthEventType.host_not_mounted, {
|
|
284
|
+
campaign_key: campaignKey,
|
|
285
|
+
payload_id: cepCampaignId,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
262
289
|
}
|
|
263
290
|
|
|
264
|
-
|
|
265
|
-
|
|
291
|
+
if (!campaign) {
|
|
292
|
+
this._log(`campaign_key_mismatch: no campaign found for key="${campaignKey}"`);
|
|
293
|
+
digiaHealthReporter.report(HealthEventType.campaign_key_mismatch, {
|
|
294
|
+
campaign_key: campaignKey,
|
|
295
|
+
payload_id: cepCampaignId,
|
|
296
|
+
available_campaign_keys: [...this._campaignsByKey.keys()],
|
|
297
|
+
});
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
this._activePayloads.set(cepCampaignId, payload);
|
|
302
|
+
nativeDigiaModule.triggerCampaign(cepCampaignId, bridgeContent, cepMetadata);
|
|
266
303
|
}
|
|
267
304
|
|
|
268
305
|
onCampaignInvalidated(campaignId: string): void {
|
|
@@ -292,7 +329,7 @@ class DigiaClass implements DigiaDelegate {
|
|
|
292
329
|
|
|
293
330
|
private _fireCustomEvent(
|
|
294
331
|
eventName: string,
|
|
295
|
-
|
|
332
|
+
_properties?: Record<string, unknown>,
|
|
296
333
|
context?: ActionContext,
|
|
297
334
|
): void {
|
|
298
335
|
const payload = context ? this._activePayloads.get(context.campaign_id) : null;
|
|
@@ -306,24 +343,25 @@ class DigiaClass implements DigiaDelegate {
|
|
|
306
343
|
private _forwardExperienceEvent(
|
|
307
344
|
data: { campaignId: string; type: string; elementId?: string },
|
|
308
345
|
): void {
|
|
346
|
+
console.log(`[Digia] received overlay event from native: campaignId=${data.campaignId} type=${data.type} elementId=${data.elementId}`);
|
|
309
347
|
const payload = this._activePayloads.get(data.campaignId);
|
|
310
348
|
if (!payload) return;
|
|
311
349
|
|
|
312
|
-
const campaignKey =
|
|
350
|
+
const { campaignKey } = payload;
|
|
313
351
|
|
|
314
352
|
let event: DigiaExperienceEvent;
|
|
315
353
|
switch (data.type) {
|
|
316
354
|
case 'impressed':
|
|
317
355
|
event = { type: 'impressed' };
|
|
318
|
-
|
|
356
|
+
void this._bumpFrequencyImpression(campaignKey);
|
|
319
357
|
break;
|
|
320
358
|
case 'clicked':
|
|
321
359
|
event = { type: 'clicked', elementId: data.elementId };
|
|
322
|
-
|
|
360
|
+
void this._applyStopOn(campaignKey, 'click');
|
|
323
361
|
break;
|
|
324
362
|
case 'dismissed':
|
|
325
363
|
event = { type: 'dismissed' };
|
|
326
|
-
|
|
364
|
+
void this._applyStopOn(campaignKey, 'dismiss');
|
|
327
365
|
this._activePayloads.delete(data.campaignId);
|
|
328
366
|
break;
|
|
329
367
|
default:
|
|
@@ -339,10 +377,21 @@ class DigiaClass implements DigiaDelegate {
|
|
|
339
377
|
campaignKey: string,
|
|
340
378
|
campaignId: string,
|
|
341
379
|
): void {
|
|
380
|
+
console.log(`[Digia] guide lifecycle event: type=${event.type} step=${event.stepIndex + 1}/${event.stepTotal} anchorKey=${event.anchorKey} displayStyle=${event.displayStyle} campaignKey=${campaignKey}`);
|
|
342
381
|
const eventName = this._guideEventName(event.type);
|
|
343
382
|
const properties = this._buildGuideProperties(event, campaignId, campaignKey);
|
|
344
383
|
this._plugins.forEach((p) => p.track?.(eventName, properties));
|
|
345
384
|
|
|
385
|
+
// Forward main experience events to native analytics.
|
|
386
|
+
// step_* and completed events are guide-specific and have no native equivalent.
|
|
387
|
+
if (event.type === 'viewed') {
|
|
388
|
+
nativeDigiaModule.trackEvent('impressed', campaignId, campaignKey, 'guide', null);
|
|
389
|
+
} else if (event.type === 'clicked') {
|
|
390
|
+
nativeDigiaModule.trackEvent('clicked', campaignId, campaignKey, 'guide', event.elementId ?? null);
|
|
391
|
+
} else if (event.type === 'dismissed') {
|
|
392
|
+
nativeDigiaModule.trackEvent('dismissed', campaignId, campaignKey, 'guide', null);
|
|
393
|
+
}
|
|
394
|
+
|
|
346
395
|
if (event.type === 'viewed') {
|
|
347
396
|
void this._bumpFrequencyImpression(campaignKey);
|
|
348
397
|
}
|
|
@@ -442,7 +491,7 @@ class DigiaClass implements DigiaDelegate {
|
|
|
442
491
|
this._log(`loaded ${campaigns.length} campaign(s): [${[...this._campaignsByKey.keys()].join(', ')}]`);
|
|
443
492
|
} catch (e) {
|
|
444
493
|
const reason = e instanceof Error ? e.message : String(e);
|
|
445
|
-
this.
|
|
494
|
+
this._error(`Campaign fetch failed: ${reason} — check your apiKey and network connectivity`);
|
|
446
495
|
digiaHealthReporter.report(HealthEventType.fetch_failed, {
|
|
447
496
|
error_code: 0,
|
|
448
497
|
platform: 'react_native',
|
|
@@ -456,7 +505,7 @@ class DigiaClass implements DigiaDelegate {
|
|
|
456
505
|
method: 'POST',
|
|
457
506
|
headers: {
|
|
458
507
|
'Content-Type': 'application/json',
|
|
459
|
-
'x-digia-project-id': this.
|
|
508
|
+
'x-digia-project-id': this._apiKey,
|
|
460
509
|
'x-digia-device-id': this._deviceId,
|
|
461
510
|
},
|
|
462
511
|
body: JSON.stringify(body),
|
|
@@ -506,39 +555,6 @@ class DigiaClass implements DigiaDelegate {
|
|
|
506
555
|
}
|
|
507
556
|
}
|
|
508
557
|
|
|
509
|
-
private _extractCampaignKey(payload: InAppPayload): string | null {
|
|
510
|
-
const fromContent = this._extractString(payload.content, 'digia_campaign_key', 'digiaKey', 'campaign_key', 'campaignKey');
|
|
511
|
-
if (fromContent) return fromContent;
|
|
512
|
-
|
|
513
|
-
const args = payload.content.args;
|
|
514
|
-
if (args && typeof args === 'object' && !Array.isArray(args)) {
|
|
515
|
-
const fromArgs = this._extractString(args as Record<string, unknown>, 'digia_campaign_key', 'digiaKey', 'campaign_key', 'campaignKey');
|
|
516
|
-
if (fromArgs) return fromArgs;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (this._campaignsByKey.has(payload.id)) return payload.id;
|
|
520
|
-
return null;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
private _extractVariables(payload: InAppPayload): Record<string, string> | undefined {
|
|
524
|
-
const fromContent = parseVariableMap(payload.content.variables);
|
|
525
|
-
if (fromContent) return fromContent;
|
|
526
|
-
|
|
527
|
-
const args = payload.content.args;
|
|
528
|
-
if (args && typeof args === 'object' && !Array.isArray(args)) {
|
|
529
|
-
return parseVariableMap((args as Record<string, unknown>).variables);
|
|
530
|
-
}
|
|
531
|
-
return undefined;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
private _extractString(data: Record<string, unknown>, ...keys: string[]): string | null {
|
|
535
|
-
for (const key of keys) {
|
|
536
|
-
const value = data[key];
|
|
537
|
-
if (typeof value === 'string' && value.trim()) return value.trim();
|
|
538
|
-
}
|
|
539
|
-
return null;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
558
|
private _parseTemplateConfig(campaign: SdkCampaign): TemplateConfig | null {
|
|
543
559
|
const c = campaign as unknown as Record<string, unknown>;
|
|
544
560
|
const raw = c.templateConfig as Record<string, unknown> | undefined;
|
|
@@ -622,6 +638,18 @@ class DigiaClass implements DigiaDelegate {
|
|
|
622
638
|
console.log(`[Digia] ${message}`);
|
|
623
639
|
}
|
|
624
640
|
|
|
641
|
+
private _warn(message: string): void {
|
|
642
|
+
if (this._logLevel === 'none') return;
|
|
643
|
+
// eslint-disable-next-line no-console
|
|
644
|
+
console.warn(`[Digia] ${message}`);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private _error(message: string): void {
|
|
648
|
+
if (this._logLevel === 'none') return;
|
|
649
|
+
// eslint-disable-next-line no-console
|
|
650
|
+
console.error(`[Digia] ${message}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
625
653
|
}
|
|
626
654
|
|
|
627
655
|
export const Digia = new DigiaClass();
|
package/src/DigiaAnchorView.tsx
CHANGED
|
@@ -47,7 +47,12 @@ export const DigiaAnchorView = forwardRef<DigiaAnchorViewRef, Props>(
|
|
|
47
47
|
const measure = useCallback(() => {
|
|
48
48
|
if (!canMeasure.current) return;
|
|
49
49
|
viewRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
|
|
50
|
-
if (width === 0 && height === 0)
|
|
50
|
+
if (width === 0 && height === 0) {
|
|
51
|
+
// Publish 0×0 so overlay subscribers can detect a collapsed/hidden
|
|
52
|
+
// anchor and cancel the campaign rather than hanging indefinitely.
|
|
53
|
+
digiaAnchorRegistry.setLayout(anchorKey, { pageX, pageY, width: 0, height: 0 });
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
51
56
|
nativeDigiaModule.registerAnchor(anchorKey, Math.round(pageX), Math.round(pageY), Math.round(width), Math.round(height));
|
|
52
57
|
digiaAnchorRegistry.setLayout(anchorKey, { pageX, pageY, width, height });
|
|
53
58
|
});
|