@digia-engage/core 2.0.0-rc.1 → 2.0.0-rc.2
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/android/build.gradle +1 -1
- package/lib/commonjs/Digia.js +90 -2
- package/lib/commonjs/Digia.js.map +1 -1
- package/lib/commonjs/DigiaAnchorView.js +35 -3
- package/lib/commonjs/DigiaAnchorView.js.map +1 -1
- package/lib/commonjs/DigiaProvider.js +2 -0
- package/lib/commonjs/DigiaProvider.js.map +1 -1
- package/lib/commonjs/frequencyEvaluator.js +70 -0
- package/lib/commonjs/frequencyEvaluator.js.map +1 -0
- package/lib/commonjs/frequencyStore.js +70 -0
- package/lib/commonjs/frequencyStore.js.map +1 -0
- package/lib/module/Digia.js +89 -2
- package/lib/module/Digia.js.map +1 -1
- package/lib/module/DigiaAnchorView.js +33 -1
- package/lib/module/DigiaAnchorView.js.map +1 -1
- package/lib/module/DigiaProvider.js +2 -0
- package/lib/module/DigiaProvider.js.map +1 -1
- package/lib/module/frequencyEvaluator.js +61 -0
- package/lib/module/frequencyEvaluator.js.map +1 -0
- package/lib/module/frequencyStore.js +64 -0
- package/lib/module/frequencyStore.js.map +1 -0
- package/lib/typescript/Digia.d.ts +6 -1
- package/lib/typescript/Digia.d.ts.map +1 -1
- package/lib/typescript/DigiaAnchorView.d.ts +5 -1
- package/lib/typescript/DigiaAnchorView.d.ts.map +1 -1
- package/lib/typescript/DigiaProvider.d.ts.map +1 -1
- package/lib/typescript/frequencyEvaluator.d.ts +14 -0
- package/lib/typescript/frequencyEvaluator.d.ts.map +1 -0
- package/lib/typescript/frequencyStore.d.ts +7 -0
- package/lib/typescript/frequencyStore.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +23 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/Digia.ts +99 -1
- package/src/DigiaAnchorView.tsx +30 -2
- package/src/DigiaProvider.tsx +2 -0
- package/src/frequencyEvaluator.ts +57 -0
- package/src/frequencyStore.ts +79 -0
- package/src/types.ts +30 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { FrequencyState } from './types';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
4
|
+
const STORE_META_KEY = 'digia:freq:__meta__';
|
|
5
|
+
|
|
6
|
+
type AsyncStorageAdapter = {
|
|
7
|
+
getItem(key: string): Promise<string | null>;
|
|
8
|
+
setItem(key: string, value: string): Promise<void>;
|
|
9
|
+
removeItem(key: string): Promise<void>;
|
|
10
|
+
getAllKeys(): Promise<readonly string[]>;
|
|
11
|
+
multiRemove(keys: string[]): Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let _storage: AsyncStorageAdapter | null = null;
|
|
15
|
+
|
|
16
|
+
const _loadStorage = (): AsyncStorageAdapter | null => {
|
|
17
|
+
try {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
|
+
const mod = require('@react-native-async-storage/async-storage');
|
|
20
|
+
return mod.default ?? mod;
|
|
21
|
+
} catch {
|
|
22
|
+
console.warn('[Digia] AsyncStorage unavailable — frequency state is in-memory only (resets on app restart)');
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getStorage = (): AsyncStorageAdapter | null => {
|
|
28
|
+
if (_storage === undefined) {
|
|
29
|
+
_storage = _loadStorage();
|
|
30
|
+
}
|
|
31
|
+
return _storage;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const _sessionStore = new Map<string, FrequencyState>();
|
|
35
|
+
|
|
36
|
+
const storeKey = (campaignKey: string) => `digia:freq:${campaignKey}`;
|
|
37
|
+
|
|
38
|
+
export const frequencyStore = {
|
|
39
|
+
async checkProjectId(projectId: string): Promise<void> {
|
|
40
|
+
const storage = getStorage();
|
|
41
|
+
if (!storage) return;
|
|
42
|
+
try {
|
|
43
|
+
const stored = await storage.getItem(STORE_META_KEY);
|
|
44
|
+
const meta = stored ? (JSON.parse(stored) as { projectId: string }) : null;
|
|
45
|
+
if (meta && meta.projectId !== projectId) {
|
|
46
|
+
const keys = await storage.getAllKeys();
|
|
47
|
+
const digiaKeys = keys.filter((k) => k.startsWith('digia:freq:'));
|
|
48
|
+
if (digiaKeys.length > 0) await storage.multiRemove([...digiaKeys]);
|
|
49
|
+
}
|
|
50
|
+
await storage.setItem(STORE_META_KEY, JSON.stringify({ projectId }));
|
|
51
|
+
} catch {
|
|
52
|
+
// non-fatal
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
async get(campaignKey: string, isSession: boolean): Promise<FrequencyState | null> {
|
|
57
|
+
if (isSession) return _sessionStore.get(campaignKey) ?? null;
|
|
58
|
+
const storage = getStorage();
|
|
59
|
+
if (!storage) return _sessionStore.get(campaignKey) ?? null;
|
|
60
|
+
try {
|
|
61
|
+
const raw = await storage.getItem(storeKey(campaignKey));
|
|
62
|
+
return raw ? (JSON.parse(raw) as FrequencyState) : null;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
async set(campaignKey: string, state: FrequencyState, isSession: boolean): Promise<void> {
|
|
69
|
+
_sessionStore.set(campaignKey, state);
|
|
70
|
+
if (isSession) return;
|
|
71
|
+
const storage = getStorage();
|
|
72
|
+
if (!storage) return;
|
|
73
|
+
try {
|
|
74
|
+
await storage.setItem(storeKey(campaignKey), JSON.stringify(state));
|
|
75
|
+
} catch {
|
|
76
|
+
// non-fatal: state already updated in-memory above
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -70,7 +70,7 @@ export type GuideLifecycleEvent =
|
|
|
70
70
|
*/
|
|
71
71
|
export interface DigiaDelegate {
|
|
72
72
|
/** Deliver a campaign payload into the Digia rendering engine. */
|
|
73
|
-
onCampaignTriggered(payload: InAppPayload): void
|
|
73
|
+
onCampaignTriggered(payload: InAppPayload): void | Promise<void>;
|
|
74
74
|
/** Invalidate / dismiss a campaign by its ID. */
|
|
75
75
|
onCampaignInvalidated(campaignId: string): void;
|
|
76
76
|
}
|
|
@@ -134,6 +134,35 @@ export type InAppBrowserAdapter = {
|
|
|
134
134
|
open: (url: string) => Promise<void>;
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
+
// ─── Frequency capping ────────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
export interface FrequencyWindow {
|
|
140
|
+
count: number;
|
|
141
|
+
window: 'session' | 'day' | 'week' | 'month';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface FrequencyPolicy {
|
|
145
|
+
max_total: number | null;
|
|
146
|
+
max_per_window: FrequencyWindow | null;
|
|
147
|
+
stop_on: 'click' | 'dismiss' | 'any_action' | null;
|
|
148
|
+
min_gap_ms?: number | null; // reserved — not evaluated in v1
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface FrequencyState {
|
|
152
|
+
shown_count: number;
|
|
153
|
+
first_shown_at: number | null; // ms timestamp — set on first impression
|
|
154
|
+
last_shown_at: number | null; // ms timestamp — reserved for min_gap_ms
|
|
155
|
+
stopped_at: number | null;
|
|
156
|
+
stopped_reason: string | null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type FrequencySkipReason = 'max_total' | 'window' | 'stopped';
|
|
160
|
+
|
|
161
|
+
export interface FrequencyEvalResult {
|
|
162
|
+
allow: boolean;
|
|
163
|
+
reason: FrequencySkipReason | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
137
166
|
// ─── SDK init config ──────────────────────────────────────────────────────────
|
|
138
167
|
|
|
139
168
|
/**
|