@apex-inc/capacitor-plugin 2.4.0 → 2.5.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.
Files changed (63) hide show
  1. package/README.md +41 -4
  2. package/android/src/main/java/inc/apex/capacitor/ApexCapacitorPlugin.kt +80 -5
  3. package/android/src/main/java/inc/apex/capacitor/ApexEvents.kt +43 -5
  4. package/android/src/main/java/inc/apex/capacitor/DeepLinkManager.kt +27 -0
  5. package/dist/deferred-link.d.ts +73 -0
  6. package/dist/deferred-link.d.ts.map +1 -0
  7. package/dist/deferred-link.js +71 -0
  8. package/dist/deferred-link.js.map +1 -0
  9. package/dist/definitions.d.ts +76 -4
  10. package/dist/definitions.d.ts.map +1 -1
  11. package/dist/esm/deferred-link.d.ts +73 -0
  12. package/dist/esm/deferred-link.d.ts.map +1 -0
  13. package/dist/esm/deferred-link.js +68 -0
  14. package/dist/esm/deferred-link.js.map +1 -0
  15. package/dist/esm/definitions.d.ts +76 -4
  16. package/dist/esm/definitions.d.ts.map +1 -1
  17. package/dist/esm/events.d.ts +33 -1
  18. package/dist/esm/events.d.ts.map +1 -1
  19. package/dist/esm/events.js +35 -1
  20. package/dist/esm/events.js.map +1 -1
  21. package/dist/esm/index.d.ts +9 -0
  22. package/dist/esm/index.d.ts.map +1 -1
  23. package/dist/esm/index.js +157 -1
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/referrer-link.d.ts +36 -0
  26. package/dist/esm/referrer-link.d.ts.map +1 -0
  27. package/dist/esm/referrer-link.js +103 -0
  28. package/dist/esm/referrer-link.js.map +1 -0
  29. package/dist/esm/skan-conversion-values.d.ts +175 -0
  30. package/dist/esm/skan-conversion-values.d.ts.map +1 -0
  31. package/dist/esm/skan-conversion-values.js +323 -0
  32. package/dist/esm/skan-conversion-values.js.map +1 -0
  33. package/dist/esm/web.d.ts +6 -1
  34. package/dist/esm/web.d.ts.map +1 -1
  35. package/dist/esm/web.js +32 -4
  36. package/dist/esm/web.js.map +1 -1
  37. package/dist/events.d.ts +33 -1
  38. package/dist/events.d.ts.map +1 -1
  39. package/dist/events.js +35 -1
  40. package/dist/events.js.map +1 -1
  41. package/dist/index.d.ts +9 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +166 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/referrer-link.d.ts +36 -0
  46. package/dist/referrer-link.d.ts.map +1 -0
  47. package/dist/referrer-link.js +107 -0
  48. package/dist/referrer-link.js.map +1 -0
  49. package/dist/skan-conversion-values.d.ts +175 -0
  50. package/dist/skan-conversion-values.d.ts.map +1 -0
  51. package/dist/skan-conversion-values.js +331 -0
  52. package/dist/skan-conversion-values.js.map +1 -0
  53. package/dist/web.d.ts +6 -1
  54. package/dist/web.d.ts.map +1 -1
  55. package/dist/web.js +32 -4
  56. package/dist/web.js.map +1 -1
  57. package/ios/Sources/ApexCapacitorPlugin/ApexEvents.swift +43 -5
  58. package/ios/Sources/ApexCapacitorPlugin/DeepLinkManager.swift +16 -2
  59. package/ios/Sources/ApexCapacitorPlugin/SkanManager.swift +18 -4
  60. package/ios/Sources/ApexCapacitorPluginBridge/ApexCapacitorPlugin.swift +22 -6
  61. package/ios/Tests/ApexCapacitorPluginTests/DeepLinkManagerTests.swift +26 -0
  62. package/ios/Tests/ApexCapacitorPluginTests/SkanManagerTests.swift +22 -1
  63. package/package.json +1 -1
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Automatic SKAdNetwork conversion values.
3
+ *
4
+ * The shop answers one question in Set up Apex ("which event means an
5
+ * install was worth it?") and Apex turns it into a table of what Apple's
6
+ * 0–63 numbers mean for the app. This module reads that table and, every
7
+ * time the app tracks an event that appears in it, tells Apple the new
8
+ * value — so the shop never writes `updateConversionValue` by hand.
9
+ *
10
+ * Behaviour, in order of importance:
11
+ *
12
+ * - **Manual wins.** The first time the app calls
13
+ * `Apex.updateConversionValue` itself, automatic updates stop for
14
+ * that install. A shop that hand-rolls its ladder keeps its ladder.
15
+ * - **Values only go up.** Apple keeps the last value it was given, and
16
+ * every network reads the ladder as "higher means more". Within a
17
+ * postback window the plugin never sends a lower value than it has
18
+ * already sent.
19
+ * - **Never in the way.** The schema is fetched once per day and cached;
20
+ * a slow or unreachable Apex means the app runs with yesterday's
21
+ * table (or none), never a delayed first screen.
22
+ *
23
+ * SKAN 4 windows, counted from first launch: window 1 covers days 0–2,
24
+ * window 2 days 3–7, window 3 days 8–35. After day 35 Apple is no longer
25
+ * listening and nothing is sent.
26
+ *
27
+ * Pure TypeScript on purpose: one HTTPS call and a little arithmetic, no
28
+ * platform APIs, so it runs identically under the native iOS bridge and
29
+ * in browser preview (where the update itself is a no-op).
30
+ */
31
+ import type { SkanCoarseValue } from "./definitions";
32
+ export type SkanWindow = 1 | 2 | 3;
33
+ export interface SkanConversionValueEntry {
34
+ eventName: string;
35
+ fineValue: number;
36
+ coarseValue: SkanCoarseValue;
37
+ lockWindow?: boolean;
38
+ }
39
+ export interface SkanConversionWindow {
40
+ window: SkanWindow;
41
+ values: SkanConversionValueEntry[];
42
+ }
43
+ export interface SkanConversionSchema {
44
+ windows: SkanConversionWindow[];
45
+ updatedAt: string;
46
+ }
47
+ /** What {@link fetchSkanConversionSchema} and the cache carry. */
48
+ export interface SkanSchemaSnapshot {
49
+ schema: SkanConversionSchema | null;
50
+ mobileAppId: string | null;
51
+ /** Weak ETag from the server, replayed as `If-None-Match`. */
52
+ etag: string | null;
53
+ /** Epoch ms when this snapshot was confirmed fresh. */
54
+ fetchedAt: number;
55
+ }
56
+ export interface FetchSkanSchemaOptions {
57
+ apiUrl: string;
58
+ workspaceKey: string;
59
+ mobileAppId?: string | null;
60
+ /** Previous ETag; a matching server tag returns `not_modified`. */
61
+ etag?: string | null;
62
+ /** Abort after this many ms. Defaults to 5000. */
63
+ timeoutMs?: number;
64
+ fetch?: typeof fetch;
65
+ }
66
+ export type FetchSkanSchemaResult = {
67
+ status: "fresh";
68
+ snapshot: SkanSchemaSnapshot;
69
+ } | {
70
+ status: "not_modified";
71
+ } | {
72
+ status: "error";
73
+ };
74
+ export declare function fetchSkanConversionSchema(options: FetchSkanSchemaOptions, now?: () => number): Promise<FetchSkanSchemaResult>;
75
+ /**
76
+ * Keep only rungs the plugin can act on. The server validates on write,
77
+ * but a cached snapshot may outlive a schema change, so be strict here
78
+ * too: a bad rung is dropped, never sent to Apple.
79
+ */
80
+ export declare function normalizeSchema(raw: SkanConversionSchema | null | undefined): SkanConversionSchema | null;
81
+ /**
82
+ * Which SKAN 4 postback window a moment falls in, counted from first
83
+ * launch. Null once Apple has stopped listening (after day 35).
84
+ */
85
+ export declare function skanWindowAt(installedAt: number, now: number): SkanWindow | null;
86
+ /** What to tell Apple, when an event maps and is worth telling. */
87
+ export interface ConversionValueUpdate {
88
+ fineValue: number;
89
+ coarseValue: SkanCoarseValue;
90
+ lockWindow?: boolean;
91
+ window: SkanWindow;
92
+ }
93
+ /**
94
+ * Decide whether tracking `eventName` should change Apple's value.
95
+ * Returns null when the event has no meaning in the current window or
96
+ * when the mapped value would not move the ladder up.
97
+ */
98
+ export declare function pickConversionValue(schema: SkanConversionSchema | null, eventName: string, ctx: {
99
+ installedAt: number;
100
+ now: number;
101
+ highestSent: number | null;
102
+ }): ConversionValueUpdate | null;
103
+ /** Minimal key/value store; `localStorage` fits, so does a Map in tests. */
104
+ export interface SkanValueStore {
105
+ getItem(key: string): string | null;
106
+ setItem(key: string, value: string): void;
107
+ }
108
+ export declare const SKAN_STORAGE_KEYS: {
109
+ readonly snapshot: "apex_skan_schema_v1";
110
+ readonly installedAt: "apex_skan_installed_at";
111
+ readonly manual: "apex_skan_manual";
112
+ readonly highest: "apex_skan_highest_v1";
113
+ };
114
+ /** How long a cached schema is trusted before revalidating. */
115
+ export declare const SKAN_SCHEMA_MAX_AGE_MS: number;
116
+ export interface SkanAutoConversionValuesOptions {
117
+ /** Sends the value to Apple (the bridge's `updateConversionValue`). */
118
+ update: (value: {
119
+ fineValue: number;
120
+ coarseValue?: SkanCoarseValue;
121
+ lockWindow?: boolean;
122
+ }) => Promise<void>;
123
+ store?: SkanValueStore | null;
124
+ fetch?: typeof fetch;
125
+ now?: () => number;
126
+ /** Debug sink; receives one line per decision when set. */
127
+ log?: (message: string) => void;
128
+ }
129
+ /**
130
+ * Owns the cached schema and the "what have I already told Apple"
131
+ * bookkeeping for one install. Created by the plugin proxy on
132
+ * `initialize({ autoConversionValues: true })`; not something an app
133
+ * constructs itself.
134
+ */
135
+ export declare class SkanAutoConversionValues {
136
+ private readonly update;
137
+ private readonly store;
138
+ private readonly fetchImpl?;
139
+ private readonly now;
140
+ private readonly log?;
141
+ private snapshot;
142
+ private installedAt;
143
+ private manual;
144
+ private highest;
145
+ private ready;
146
+ private endpoint;
147
+ constructor(options: SkanAutoConversionValuesOptions);
148
+ /**
149
+ * Point at a workspace and refresh the schema if the cache is stale.
150
+ * Resolves as soon as the cache has been read; the network revalidate
151
+ * runs in the background and never blocks the caller.
152
+ */
153
+ initialize(endpoint: {
154
+ apiUrl: string;
155
+ workspaceKey: string;
156
+ mobileAppId?: string | null;
157
+ }): Promise<void>;
158
+ /** Force a network revalidation (ETag-aware). */
159
+ revalidate(): Promise<void>;
160
+ /** Wait for any in-flight revalidation (tests and debug UIs). */
161
+ whenReady(): Promise<void>;
162
+ /** The schema the plugin is acting on right now. */
163
+ getSchema(): SkanSchemaSnapshot;
164
+ /** True once the app has called `updateConversionValue` itself. */
165
+ get manualMode(): boolean;
166
+ /** Called when the app updates Apple's value by hand. Auto steps aside. */
167
+ noteManualUpdate(): void;
168
+ /**
169
+ * Called after every `track`. Sends the mapped value when the event has
170
+ * one in the current window and it moves the ladder up.
171
+ */
172
+ onTrack(eventName: string): Promise<ConversionValueUpdate | null>;
173
+ private readInstalledAt;
174
+ }
175
+ //# sourceMappingURL=skan-conversion-values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skan-conversion-values.d.ts","sourceRoot":"","sources":["../src/skan-conversion-values.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,331 @@
1
+ "use strict";
2
+ /**
3
+ * Automatic SKAdNetwork conversion values.
4
+ *
5
+ * The shop answers one question in Set up Apex ("which event means an
6
+ * install was worth it?") and Apex turns it into a table of what Apple's
7
+ * 0–63 numbers mean for the app. This module reads that table and, every
8
+ * time the app tracks an event that appears in it, tells Apple the new
9
+ * value — so the shop never writes `updateConversionValue` by hand.
10
+ *
11
+ * Behaviour, in order of importance:
12
+ *
13
+ * - **Manual wins.** The first time the app calls
14
+ * `Apex.updateConversionValue` itself, automatic updates stop for
15
+ * that install. A shop that hand-rolls its ladder keeps its ladder.
16
+ * - **Values only go up.** Apple keeps the last value it was given, and
17
+ * every network reads the ladder as "higher means more". Within a
18
+ * postback window the plugin never sends a lower value than it has
19
+ * already sent.
20
+ * - **Never in the way.** The schema is fetched once per day and cached;
21
+ * a slow or unreachable Apex means the app runs with yesterday's
22
+ * table (or none), never a delayed first screen.
23
+ *
24
+ * SKAN 4 windows, counted from first launch: window 1 covers days 0–2,
25
+ * window 2 days 3–7, window 3 days 8–35. After day 35 Apple is no longer
26
+ * listening and nothing is sent.
27
+ *
28
+ * Pure TypeScript on purpose: one HTTPS call and a little arithmetic, no
29
+ * platform APIs, so it runs identically under the native iOS bridge and
30
+ * in browser preview (where the update itself is a no-op).
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.SkanAutoConversionValues = exports.SKAN_SCHEMA_MAX_AGE_MS = exports.SKAN_STORAGE_KEYS = void 0;
34
+ exports.fetchSkanConversionSchema = fetchSkanConversionSchema;
35
+ exports.normalizeSchema = normalizeSchema;
36
+ exports.skanWindowAt = skanWindowAt;
37
+ exports.pickConversionValue = pickConversionValue;
38
+ const DEFAULT_TIMEOUT_MS = 5000;
39
+ async function fetchSkanConversionSchema(options, now = Date.now) {
40
+ const { apiUrl, workspaceKey, mobileAppId } = options;
41
+ if (!workspaceKey)
42
+ return { status: "error" };
43
+ const doFetch = options.fetch ?? globalThis.fetch;
44
+ if (typeof doFetch !== "function")
45
+ return { status: "error" };
46
+ const controller = new AbortController();
47
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
48
+ try {
49
+ const url = new URL(`${apiUrl.replace(/\/+$/, "")}/api/mobile/skan/schema/resolve`);
50
+ url.searchParams.set("workspace", workspaceKey);
51
+ if (mobileAppId)
52
+ url.searchParams.set("mobileAppId", mobileAppId);
53
+ const headers = {
54
+ "x-apex-workspace": workspaceKey,
55
+ };
56
+ if (options.etag)
57
+ headers["If-None-Match"] = options.etag;
58
+ const response = await doFetch(url.toString(), {
59
+ method: "GET",
60
+ headers,
61
+ signal: controller.signal,
62
+ });
63
+ if (response.status === 304)
64
+ return { status: "not_modified" };
65
+ if (!response.ok)
66
+ return { status: "error" };
67
+ const payload = (await response.json());
68
+ return {
69
+ status: "fresh",
70
+ snapshot: {
71
+ schema: normalizeSchema(payload.data?.schema),
72
+ mobileAppId: payload.data?.mobileAppId ?? null,
73
+ etag: response.headers.get("etag"),
74
+ fetchedAt: now(),
75
+ },
76
+ };
77
+ }
78
+ catch {
79
+ return { status: "error" };
80
+ }
81
+ finally {
82
+ clearTimeout(timer);
83
+ }
84
+ }
85
+ /**
86
+ * Keep only rungs the plugin can act on. The server validates on write,
87
+ * but a cached snapshot may outlive a schema change, so be strict here
88
+ * too: a bad rung is dropped, never sent to Apple.
89
+ */
90
+ function normalizeSchema(raw) {
91
+ if (!raw || !Array.isArray(raw.windows))
92
+ return null;
93
+ const windows = [];
94
+ for (const w of raw.windows) {
95
+ if (!w || (w.window !== 1 && w.window !== 2 && w.window !== 3))
96
+ continue;
97
+ if (!Array.isArray(w.values))
98
+ continue;
99
+ const values = w.values.filter((v) => !!v &&
100
+ typeof v.eventName === "string" &&
101
+ v.eventName.length > 0 &&
102
+ Number.isInteger(v.fineValue) &&
103
+ v.fineValue >= 0 &&
104
+ v.fineValue <= 63 &&
105
+ (v.coarseValue === "low" ||
106
+ v.coarseValue === "medium" ||
107
+ v.coarseValue === "high"));
108
+ windows.push({ window: w.window, values });
109
+ }
110
+ return {
111
+ windows,
112
+ updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : "",
113
+ };
114
+ }
115
+ // ─── Window arithmetic ────────────────────────────────────────────────────
116
+ const DAY_MS = 24 * 60 * 60 * 1000;
117
+ /**
118
+ * Which SKAN 4 postback window a moment falls in, counted from first
119
+ * launch. Null once Apple has stopped listening (after day 35).
120
+ */
121
+ function skanWindowAt(installedAt, now) {
122
+ const elapsed = now - installedAt;
123
+ if (elapsed < 0)
124
+ return 1;
125
+ if (elapsed < 2 * DAY_MS)
126
+ return 1;
127
+ if (elapsed < 7 * DAY_MS)
128
+ return 2;
129
+ if (elapsed < 35 * DAY_MS)
130
+ return 3;
131
+ return null;
132
+ }
133
+ /**
134
+ * Decide whether tracking `eventName` should change Apple's value.
135
+ * Returns null when the event has no meaning in the current window or
136
+ * when the mapped value would not move the ladder up.
137
+ */
138
+ function pickConversionValue(schema, eventName, ctx) {
139
+ if (!schema)
140
+ return null;
141
+ const window = skanWindowAt(ctx.installedAt, ctx.now);
142
+ if (!window)
143
+ return null;
144
+ const entry = schema.windows
145
+ .find((w) => w.window === window)
146
+ ?.values.find((v) => v.eventName === eventName);
147
+ if (!entry)
148
+ return null;
149
+ if (ctx.highestSent !== null && entry.fineValue <= ctx.highestSent) {
150
+ return null;
151
+ }
152
+ return {
153
+ fineValue: entry.fineValue,
154
+ coarseValue: entry.coarseValue,
155
+ ...(entry.lockWindow ? { lockWindow: true } : {}),
156
+ window,
157
+ };
158
+ }
159
+ exports.SKAN_STORAGE_KEYS = {
160
+ snapshot: "apex_skan_schema_v1",
161
+ installedAt: "apex_skan_installed_at",
162
+ manual: "apex_skan_manual",
163
+ highest: "apex_skan_highest_v1",
164
+ };
165
+ /** How long a cached schema is trusted before revalidating. */
166
+ exports.SKAN_SCHEMA_MAX_AGE_MS = DAY_MS;
167
+ /**
168
+ * Owns the cached schema and the "what have I already told Apple"
169
+ * bookkeeping for one install. Created by the plugin proxy on
170
+ * `initialize({ autoConversionValues: true })`; not something an app
171
+ * constructs itself.
172
+ */
173
+ class SkanAutoConversionValues {
174
+ constructor(options) {
175
+ this.snapshot = null;
176
+ this.manual = false;
177
+ this.highest = {};
178
+ this.ready = Promise.resolve();
179
+ this.endpoint = null;
180
+ this.update = options.update;
181
+ this.store = options.store === undefined ? defaultStore() : options.store;
182
+ this.fetchImpl = options.fetch;
183
+ this.now = options.now ?? Date.now;
184
+ this.log = options.log;
185
+ this.installedAt = this.readInstalledAt();
186
+ this.manual = this.store?.getItem(exports.SKAN_STORAGE_KEYS.manual) === "1";
187
+ this.highest = readJson(this.store, exports.SKAN_STORAGE_KEYS.highest) ?? {};
188
+ this.snapshot = readJson(this.store, exports.SKAN_STORAGE_KEYS.snapshot);
189
+ }
190
+ /**
191
+ * Point at a workspace and refresh the schema if the cache is stale.
192
+ * Resolves as soon as the cache has been read; the network revalidate
193
+ * runs in the background and never blocks the caller.
194
+ */
195
+ initialize(endpoint) {
196
+ this.endpoint = {
197
+ apiUrl: endpoint.apiUrl,
198
+ workspaceKey: endpoint.workspaceKey,
199
+ mobileAppId: endpoint.mobileAppId ?? null,
200
+ };
201
+ const stale = !this.snapshot ||
202
+ this.now() - this.snapshot.fetchedAt >= exports.SKAN_SCHEMA_MAX_AGE_MS;
203
+ if (stale) {
204
+ this.ready = this.revalidate();
205
+ }
206
+ return Promise.resolve();
207
+ }
208
+ /** Force a network revalidation (ETag-aware). */
209
+ async revalidate() {
210
+ if (!this.endpoint)
211
+ return;
212
+ const result = await fetchSkanConversionSchema({
213
+ ...this.endpoint,
214
+ etag: this.snapshot?.etag ?? null,
215
+ fetch: this.fetchImpl,
216
+ }, this.now);
217
+ if (result.status === "fresh") {
218
+ this.snapshot = result.snapshot;
219
+ writeJson(this.store, exports.SKAN_STORAGE_KEYS.snapshot, this.snapshot);
220
+ this.log?.(`skan schema refreshed (${countRungs(this.snapshot.schema)} rungs)`);
221
+ }
222
+ else if (result.status === "not_modified" && this.snapshot) {
223
+ this.snapshot = { ...this.snapshot, fetchedAt: this.now() };
224
+ writeJson(this.store, exports.SKAN_STORAGE_KEYS.snapshot, this.snapshot);
225
+ this.log?.("skan schema unchanged");
226
+ }
227
+ else if (result.status === "error") {
228
+ this.log?.("skan schema fetch failed; keeping cached copy");
229
+ }
230
+ }
231
+ /** Wait for any in-flight revalidation (tests and debug UIs). */
232
+ whenReady() {
233
+ return this.ready;
234
+ }
235
+ /** The schema the plugin is acting on right now. */
236
+ getSchema() {
237
+ return (this.snapshot ?? {
238
+ schema: null,
239
+ mobileAppId: this.endpoint?.mobileAppId ?? null,
240
+ etag: null,
241
+ fetchedAt: 0,
242
+ });
243
+ }
244
+ /** True once the app has called `updateConversionValue` itself. */
245
+ get manualMode() {
246
+ return this.manual;
247
+ }
248
+ /** Called when the app updates Apple's value by hand. Auto steps aside. */
249
+ noteManualUpdate() {
250
+ if (this.manual)
251
+ return;
252
+ this.manual = true;
253
+ this.store?.setItem(exports.SKAN_STORAGE_KEYS.manual, "1");
254
+ this.log?.("skan manual updateConversionValue seen; auto values off");
255
+ }
256
+ /**
257
+ * Called after every `track`. Sends the mapped value when the event has
258
+ * one in the current window and it moves the ladder up.
259
+ */
260
+ async onTrack(eventName) {
261
+ if (this.manual)
262
+ return null;
263
+ const now = this.now();
264
+ const window = skanWindowAt(this.installedAt, now);
265
+ if (!window)
266
+ return null;
267
+ const pick = pickConversionValue(this.snapshot?.schema ?? null, eventName, {
268
+ installedAt: this.installedAt,
269
+ now,
270
+ highestSent: this.highest[window] ?? null,
271
+ });
272
+ if (!pick)
273
+ return null;
274
+ try {
275
+ await this.update({
276
+ fineValue: pick.fineValue,
277
+ coarseValue: pick.coarseValue,
278
+ ...(pick.lockWindow ? { lockWindow: true } : {}),
279
+ });
280
+ }
281
+ catch (err) {
282
+ this.log?.(`skan updateConversionValue failed for ${eventName}: ${String(err)}`);
283
+ return null;
284
+ }
285
+ this.highest[window] = pick.fineValue;
286
+ writeJson(this.store, exports.SKAN_STORAGE_KEYS.highest, this.highest);
287
+ this.log?.(`skan updatePostbackConversionValue(${pick.fineValue}, ${pick.coarseValue}) for ${eventName} in window ${window}`);
288
+ return pick;
289
+ }
290
+ readInstalledAt() {
291
+ const raw = this.store?.getItem(exports.SKAN_STORAGE_KEYS.installedAt);
292
+ const parsed = raw ? Number(raw) : NaN;
293
+ if (Number.isFinite(parsed) && parsed > 0)
294
+ return parsed;
295
+ const now = this.now();
296
+ this.store?.setItem(exports.SKAN_STORAGE_KEYS.installedAt, String(now));
297
+ return now;
298
+ }
299
+ }
300
+ exports.SkanAutoConversionValues = SkanAutoConversionValues;
301
+ // ─── Storage helpers ──────────────────────────────────────────────────────
302
+ function defaultStore() {
303
+ try {
304
+ const ls = globalThis.localStorage;
305
+ return ls ? { getItem: (k) => ls.getItem(k), setItem: (k, v) => ls.setItem(k, v) } : null;
306
+ }
307
+ catch {
308
+ return null;
309
+ }
310
+ }
311
+ function readJson(store, key) {
312
+ try {
313
+ const raw = store?.getItem(key);
314
+ return raw ? JSON.parse(raw) : null;
315
+ }
316
+ catch {
317
+ return null;
318
+ }
319
+ }
320
+ function writeJson(store, key, value) {
321
+ try {
322
+ store?.setItem(key, JSON.stringify(value));
323
+ }
324
+ catch {
325
+ // Private mode / quota. Worst case we refetch tomorrow's schema early.
326
+ }
327
+ }
328
+ function countRungs(schema) {
329
+ return schema?.windows.reduce((n, w) => n + w.values.length, 0) ?? 0;
330
+ }
331
+ //# sourceMappingURL=skan-conversion-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skan-conversion-values.js","sourceRoot":"","sources":["../src/skan-conversion-values.ts"],"names":[],"mappings":"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"}
package/dist/web.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  * in separate files so unit tests can cover them without DOM mocking.
12
12
  */
13
13
  import { WebPlugin } from "@capacitor/core";
14
- import type { AdvertisingIdResult, ApexCapacitorPlugin, ApexEvent, AttStatus, DeviceInfo, FlushResult, IdentifyOptions, InitializeOptions, PushRegistrationResult, QueueStatus, SessionInfo, SkanCoarseValue, VariantAssignmentResult } from "./definitions";
14
+ import type { AdvertisingIdResult, ApexCapacitorPlugin, ApexEvent, AttStatus, DeferredDeepLinkResult, DeviceInfo, FlushResult, IdentifyOptions, InitializeOptions, PushRegistrationResult, QueueStatus, SessionInfo, SkanCoarseValue, SkanSchemaSnapshot, VariantAssignmentResult } from "./definitions";
15
15
  export declare class ApexCapacitorWeb extends WebPlugin implements ApexCapacitorPlugin {
16
16
  private queue?;
17
17
  private session?;
@@ -54,6 +54,7 @@ export declare class ApexCapacitorWeb extends WebPlugin implements ApexCapacitor
54
54
  getAdvertisingId(): Promise<AdvertisingIdResult>;
55
55
  getInstallReferrer(): Promise<{
56
56
  referrer: string | null;
57
+ clickTimestamp: number;
57
58
  }>;
58
59
  getVisitorId(): Promise<{
59
60
  visitorId: string;
@@ -80,10 +81,14 @@ export declare class ApexCapacitorWeb extends WebPlugin implements ApexCapacitor
80
81
  updateConversionValue(_options: {
81
82
  fineValue: number;
82
83
  coarseValue?: SkanCoarseValue;
84
+ lockWindow?: boolean;
83
85
  }): Promise<void>;
86
+ getConversionValueSchema(): Promise<SkanSchemaSnapshot>;
84
87
  getInitialDeepLink(): Promise<{
85
88
  url: string | null;
89
+ deepLinkHint: string | null;
86
90
  }>;
91
+ getDeferredDeepLink(): Promise<DeferredDeepLinkResult | null>;
87
92
  getDeviceInfo(): Promise<DeviceInfo>;
88
93
  startSession(): Promise<{
89
94
  sessionId: string;
package/dist/web.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,UAAU,EACV,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,eAAe,CAAC;AA4GvB,qBAAa,gBAAiB,SAAQ,SAAU,YAAW,mBAAmB;IAC5E,OAAO,CAAC,KAAK,CAAC,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAiB;IACjC,OAAO,CAAC,MAAM,CAAC,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,WAAW,CAAS;IAC5B;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAQ;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,uDAAuD;IACvD,OAAO,CAAC,UAAU,CAA0B;IAC5C,0DAA0D;IAC1D,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B;;;;OAIG;IACH,OAAO,CAAC,cAAc,CAAS;IAEzB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoErD,4BAA4B,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC;IAI9D,iBAAiB,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,CAAA;KAAE,CAAC;IAIzD;;;;OAIG;IACG,4BAA4B,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAI/D,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAIhD,kBAAkB,IAAI,OAAO,CAAC;QAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IAII,YAAY,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAO9C,YAAY,CAAC,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE;;;;;;;;;;;;;;OAcG;IACG,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CjD,qBAAqB,CAAC,QAAQ,EAAE;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,eAAe,CAAC;QAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIX,wBAAwB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAOvD,kBAAkB,IAAI,OAAO,CAAC;QAClC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC7B,CAAC;IAcI,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAU7D,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC;IAoBpC,YAAY,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAM9C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC;IAQ/C;;;OAGG;IACH,OAAO,CAAC,eAAe,CAA2E;IAE5F,UAAU,CAAC,OAAO,EAAE;QACxB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA8FpC;;;;;;;;;;;OAWG;IACG,wBAAwB,CAAC,QAAQ,EAAE;QACvC,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAW3D,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAuEtC,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IASpC,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC;IAMlC,WAAW,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD,UAAU,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxD,UAAU,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAI3C,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzC,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,qBAAqB;IA0B7B;iFAC6E;IAC7E,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,iBAAiB;CAK1B"}
package/dist/web.js CHANGED
@@ -215,7 +215,7 @@ class ApexCapacitorWeb extends core_1.WebPlugin {
215
215
  return { id: null, fallback: null };
216
216
  }
217
217
  async getInstallReferrer() {
218
- return { referrer: null };
218
+ return { referrer: null, clickTimestamp: 0 };
219
219
  }
220
220
  async getVisitorId() {
221
221
  if (!this.visitorId) {
@@ -286,11 +286,34 @@ class ApexCapacitorWeb extends core_1.WebPlugin {
286
286
  async updateConversionValue(_options) {
287
287
  // No-op on web / non-iOS.
288
288
  }
289
+ async getConversionValueSchema() {
290
+ // The proxy in `index.ts` answers this from its cache on iOS. Reached
291
+ // directly only when the web fallback is used as a bare class, where
292
+ // Apple is not listening anyway.
293
+ return { schema: null, mobileAppId: null, etag: null, fetchedAt: 0 };
294
+ }
289
295
  async getInitialDeepLink() {
290
296
  if (typeof window !== "undefined" && window.location) {
291
- return { url: window.location.href };
297
+ const href = window.location.href;
298
+ let deepLinkHint = null;
299
+ try {
300
+ deepLinkHint = new URL(href).searchParams.get("apex_dl");
301
+ }
302
+ catch {
303
+ // Non-parseable location (rare, e.g. an about: page) — no hint.
304
+ }
305
+ return { url: href, deepLinkHint };
292
306
  }
293
- return { url: null };
307
+ return { url: null, deepLinkHint: null };
308
+ }
309
+ async getDeferredDeepLink() {
310
+ // Deferred deep linking exists to bridge a gap that only exists on
311
+ // native: browser tap → app store → fresh app with no shared state.
312
+ // In a browser there is no gap — the URL the user tapped is the URL
313
+ // the page is already on, and `getInitialDeepLink()` returns it.
314
+ // Claiming a deferred link here would also burn the one-shot match
315
+ // that the real app install needs.
316
+ return null;
294
317
  }
295
318
  async getDeviceInfo() {
296
319
  // Best-effort on web — mostly placeholders so callers get consistent shape.
@@ -377,7 +400,12 @@ class ApexCapacitorWeb extends core_1.WebPlugin {
377
400
  // denominator for results). Deduped per (experiment, variant); batched
378
401
  // through track() so it doesn't add a synchronous network call.
379
402
  if (result.eligible) {
380
- const expoKey = `${experimentId}:${result.variant}`;
403
+ // DBS-5 — dedupe per (session, experiment, variant) so a new session
404
+ // re-fires exactly one exposure. The exposure event itself carries the
405
+ // same sessionId (stamped in track()); this keeps the per-process
406
+ // guard aligned with the per-session Events-meter unit.
407
+ const expoSessionId = this.session?.getCurrent()?.sessionId ?? "";
408
+ const expoKey = `${expoSessionId}:${experimentId}:${result.variant}`;
381
409
  if (!firedMobileExposures.has(expoKey)) {
382
410
  firedMobileExposures.add(expoKey);
383
411
  void this.track({