@advenue/react-native 0.6.0 → 0.6.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.
@@ -0,0 +1,346 @@
1
+ import { StorageAdapter, SecureStorageAdapter, DeepLink, AdvenueConfig, AdvenueClient, TrackOptions, Consent, DeviceInfo } from '@advenue/sdk-core';
2
+ export { AdvenueConfig, Consent, DeepLink, TrackOptions } from '@advenue/sdk-core';
3
+
4
+ /**
5
+ * Minimal structural type for the bits of `react-native-mmkv`'s MMKV instance
6
+ * we use. Declared locally so this package needs no react-native types at
7
+ * compile time — the app injects a real `new MMKV()` instance at runtime.
8
+ */
9
+ interface MMKVLike {
10
+ set(key: string, value: string): void;
11
+ getString(key: string): string | undefined;
12
+ delete(key: string): void;
13
+ }
14
+ /** Wraps an MMKV instance as an Advenue StorageAdapter (synchronous, fast). */
15
+ declare function createMMKVStorage(mmkv: MMKVLike): StorageAdapter;
16
+
17
+ interface InstallReferrerResult {
18
+ referrer: string;
19
+ /** Device-clock: referrerClickTimestampSeconds. */
20
+ clickTimestamp: number;
21
+ /** Device-clock: installBeginTimestampSeconds. */
22
+ installTimestamp: number;
23
+ /**
24
+ * Server-clock: referrerClickTimestampServerSeconds (G1 fraud trust —
25
+ * referrerTrust:'server'). 0 = unverified; absent on older native builds.
26
+ */
27
+ clickServerTimestamp?: number;
28
+ /** Server-clock: installBeginTimestampServerSeconds. 0 = unverified. */
29
+ installServerTimestamp?: number;
30
+ googlePlayInstant: boolean;
31
+ }
32
+ interface MetaInstallReferrerResult {
33
+ installReferrer: string;
34
+ isClickThrough: boolean;
35
+ actualTimestamp: number;
36
+ /** Which Meta app served the referrer (e.g. com.facebook.katana). */
37
+ provider: string;
38
+ }
39
+ /**
40
+ * Device metadata for Meta CAPI `extinfo` (Task 3n). Structurally mirrors
41
+ * `DeviceInfo` from `@advenue/shared` — kept as a local subset type (rather
42
+ * than importing that package) so this native-module-only package stays
43
+ * dependency-free; the RN facade's `collectDeviceInfo()` merges it into the
44
+ * real `DeviceInfo` shape.
45
+ */
46
+ interface AdvenueDeviceInfo {
47
+ model?: string;
48
+ locale?: string;
49
+ carrier?: string;
50
+ timezone?: string;
51
+ screenWidth?: number;
52
+ screenHeight?: number;
53
+ screenDensity?: number;
54
+ cpuCores?: number;
55
+ totalStorageGb?: number;
56
+ freeStorageGb?: number;
57
+ }
58
+ interface AdvenueAndroidNativeModule {
59
+ /** Raw Play Install Referrer; parse with @advenue/install-referrer. */
60
+ getInstallReferrer(): Promise<InstallReferrerResult | null>;
61
+ /**
62
+ * Meta install referrer (null when no Facebook/Instagram app is installed);
63
+ * parse with parseMetaInstallReferrer from @advenue/install-referrer.
64
+ */
65
+ getMetaInstallReferrer(): Promise<MetaInstallReferrerResult | null>;
66
+ /** Google Advertising ID (GAID) + limit-ad-tracking flag; null when unavailable. */
67
+ getAdvertisingId(): Promise<{
68
+ id: string;
69
+ limitAdTracking: boolean;
70
+ } | null>;
71
+ /** App Set ID — non-advertising, developer-scoped fallback id; null when unavailable. */
72
+ getAppSetId(): Promise<string | null>;
73
+ /**
74
+ * Play Integrity Standard API token (G3.1n).
75
+ *
76
+ * `requestHash` MUST be sha256_hex("<appId>:<deviceId>") — lowercase hex SHA-256
77
+ * of the literal string "<appId>:<deviceId>". The server's mapIntegrityVerdict
78
+ * re-derives the same string and compares it byte-for-byte.
79
+ *
80
+ * Rejects when:
81
+ * - ECONFIG: `io.advenue.INTEGRITY_CLOUD_PROJECT_NUMBER` meta-data is absent.
82
+ * - EUNSUPPORTED: Play Services unavailable or provider warming failed.
83
+ * - EINTEGRITY: Play returned an API-level error (network, quota, etc.).
84
+ *
85
+ * The JS bridge treats any rejection as "no attestation" and omits the token
86
+ * from the install event — rejection must never block the install track call.
87
+ */
88
+ getIntegrityToken(requestHash: string): Promise<string>;
89
+ /**
90
+ * Device metadata (model, locale, screen, cpu, storage, timezone) used to
91
+ * populate Meta CAPI `extinfo` (Task 3n). Synchronous, best-effort — the JS
92
+ * facade (`collectDeviceInfo`) treats a thrown error as "unavailable" and
93
+ * degrades to `{}` rather than blocking anything.
94
+ */
95
+ getDeviceInfo(): AdvenueDeviceInfo;
96
+ /**
97
+ * Built-in SDK storage (SharedPreferences `io.advenue.sdk`, MODE_PRIVATE) —
98
+ * the durable offline buffer + SDK state, so the app never supplies storage.
99
+ * Optional: absent on native builds predating this capability; the RN facade
100
+ * feature-detects and falls back to in-memory buffering. (No secure variant:
101
+ * Android has no reinstall-durable store — a reinstall legitimately re-fires
102
+ * the install, which the backend per-device window deduplicates.)
103
+ */
104
+ storageGetItem?(key: string): string | null;
105
+ storageSetItem?(key: string, value: string): void;
106
+ storageRemoveItem?(key: string): void;
107
+ /**
108
+ * Android SSAID (Settings.Secure.ANDROID_ID) — signing-key-scoped, stable
109
+ * across reinstalls. The RN facade reads it ONLY when no usable GAID exists
110
+ * (Adjust-style fallback) and it is used strictly as a first-party
111
+ * fraud/dedup + reinstall-detection signal, never for ad attribution (Play
112
+ * policy). Optional: absent on older native builds; feature-detected.
113
+ */
114
+ getAndroidId?(): string | null;
115
+ }
116
+ type TrackingAuthorizationStatus = 'notDetermined' | 'restricted' | 'denied' | 'authorized';
117
+ interface AdvenueIosNativeModule {
118
+ registerAppForAttribution(): void;
119
+ /**
120
+ * Conversion value: fine 0–63, coarse 'low'|'medium'|'high'. Updates the
121
+ * SKAN 4.0 postback, and on iOS 17.4+ the AdAttributionKit postback too.
122
+ */
123
+ updateConversionValue(fineValue: number, coarse: string, lockWindow: boolean): Promise<void>;
124
+ /** Apple Search Ads attribution token (resolve server-side). */
125
+ getAttributionToken(): Promise<string | null>;
126
+ /**
127
+ * Shows the ATT consent prompt; requires NSUserTrackingUsageDescription in
128
+ * the app's Info.plist. Resolves with the resulting status.
129
+ */
130
+ requestTrackingAuthorization(): Promise<TrackingAuthorizationStatus>;
131
+ getTrackingAuthorizationStatus(): TrackingAuthorizationStatus;
132
+ getAdvertisingId(): Promise<string | null>;
133
+ /** Vendor-scoped device id (IDFV) — available without ATT; a fallback anchor. */
134
+ getIdentifierForVendor(): string | null;
135
+ /** Clipboard match token (advmatch:<id>) for deterministic deferred deep linking; null if absent. */
136
+ getPasteboardMatchToken(): string | null;
137
+ /**
138
+ * G3.2n — App Attest. Generates (or reuses a keychain-cached) DCAppAttest
139
+ * key, computes clientDataHash = SHA-256(challenge), and calls
140
+ * DCAppAttestService.attestKey. Resolves { keyId, attestationObject } where
141
+ * attestationObject is a base64-encoded CBOR attestation for the server.
142
+ * Rejects with code EUNSUPPORTED on simulators (isSupported == false).
143
+ */
144
+ attestKey(challenge: string): Promise<{
145
+ keyId: string;
146
+ attestationObject: string;
147
+ }>;
148
+ /**
149
+ * G3.3n — DeviceCheck. Calls DCDevice.current.generateToken to obtain the
150
+ * opaque base64 token that identifies this physical device to the Apple
151
+ * DeviceCheck API. The server queries/updates the persistent 2-bit per-device
152
+ * flag to detect reinstall abuse. Rejects with code EUNSUPPORTED on devices
153
+ * where DCDevice.current.isSupported is false (simulator, Catalyst, etc.).
154
+ */
155
+ getDeviceCheckToken(): Promise<string>;
156
+ /**
157
+ * Device metadata (model, locale, screen, cpu, storage, timezone) used to
158
+ * populate Meta CAPI `extinfo` (Task 3n). Synchronous, best-effort — the JS
159
+ * facade (`collectDeviceInfo`) treats a thrown error as "unavailable" and
160
+ * degrades to `{}` rather than blocking anything.
161
+ */
162
+ getDeviceInfo(): AdvenueDeviceInfo;
163
+ /**
164
+ * Built-in SDK storage (UserDefaults suite `io.advenue.sdk`) — the durable
165
+ * offline buffer + SDK state, so the app never supplies storage. Optional:
166
+ * absent on native builds predating this capability; the RN facade
167
+ * feature-detects and falls back to in-memory buffering.
168
+ */
169
+ storageGetItem?(key: string): string | null;
170
+ storageSetItem?(key: string, value: string): void;
171
+ storageRemoveItem?(key: string): void;
172
+ /**
173
+ * Built-in secure storage (Keychain, kSecAttrAccessibleAfterFirstUnlock,
174
+ * ThisDeviceOnly) — survives app reinstall, which is what makes the device
175
+ * identity and the install guard reinstall-resilient (Adjust-style).
176
+ * Optional: absent on older native builds; feature-detected.
177
+ */
178
+ secureGetItem?(key: string): string | null;
179
+ secureSetItem?(key: string, value: string): void;
180
+ secureRemoveItem?(key: string): void;
181
+ }
182
+
183
+ /**
184
+ * Minimal structural type for the bits of `expo-secure-store` we use. Declared
185
+ * locally so this package needs no expo types at compile time — the app passes
186
+ * the module (`import * as SecureStore from 'expo-secure-store'`) at runtime.
187
+ */
188
+ interface SecureStoreLike {
189
+ getItemAsync(key: string): Promise<string | null>;
190
+ setItemAsync(key: string, value: string): Promise<void>;
191
+ /** Optional — forwarded so GDPR erasure can wipe the durable entries. */
192
+ deleteItemAsync?(key: string): Promise<void>;
193
+ }
194
+ /** Wraps expo-secure-store as an Advenue SecureStorageAdapter (async, durable). */
195
+ declare function createSecureStore(secureStore: SecureStoreLike): SecureStorageAdapter;
196
+
197
+ /**
198
+ * Parses an OS-delivered link (Universal Link, App Link, or custom scheme) into
199
+ * the unified {@link DeepLink} shape. The `deepLinkValue` is a best-effort path
200
+ * (host + path for custom schemes, path for http(s)); the raw `url` is always
201
+ * provided so the host app can parse it itself when needed.
202
+ */
203
+ declare function parseDirectLink(url: string): DeepLink;
204
+
205
+ /**
206
+ * Lazy access to the native modules that ship inside this package (ios/ and
207
+ * android/, registered via expo-module.config.json). Host-module resolution
208
+ * goes through native-require.cjs so Metro sees literal requires (see the
209
+ * comment there); `requireNativeModule` throws when the native side isn't
210
+ * built (Expo Go, web, missing pods), so calls stay inside try/catch.
211
+ */
212
+ declare function getIosNative(): AdvenueIosNativeModule | null;
213
+ declare function getAndroidNative(): AdvenueAndroidNativeModule | null;
214
+
215
+ /**
216
+ * Resolves the device advertising id (IDFA on iOS, GAID on Android), gates it
217
+ * on ATT authorization status (iOS) / limitAdTracking flag (Android), and on
218
+ * DMA consent when the user is subject to GDPR. Pushes the result — or an
219
+ * empty object to clear — into the active client via `setAdvertisingId`.
220
+ *
221
+ * Fire-and-forget at call sites; errors are suppressed internally.
222
+ */
223
+ declare function resolveAdvertisingId(): Promise<void>;
224
+ /**
225
+ * Collects native device metadata (model, locale, screen, cpu, storage, timezone)
226
+ * used to populate Meta CAPI `extinfo`. Reads from the platform-appropriate
227
+ * native module's `getDeviceInfo()`; returns `{}` when the native module or the
228
+ * method is unavailable (bare React Native without the native SDK, web, Expo
229
+ * Go, or an older native build predating this method). Never throws — any
230
+ * native-side error degrades to an empty object so callers can unconditionally
231
+ * pass the result through.
232
+ */
233
+ declare function collectDeviceInfo(natives: {
234
+ platform: 'ios' | 'android' | string;
235
+ ios?: {
236
+ getDeviceInfo?: () => Partial<DeviceInfo>;
237
+ } | null;
238
+ android?: {
239
+ getDeviceInfo?: () => Partial<DeviceInfo>;
240
+ } | null;
241
+ }): DeviceInfo;
242
+ /**
243
+ * iOS clipboard-match deferred deep linking: reads the `advmatch:<id>` token the
244
+ * link redirector wrote to the pasteboard and exchanges it for the deep link — a
245
+ * DETERMINISTIC match (no IDFA, no fingerprinting). Returns null off iOS, when
246
+ * there's no token, or without consent. (Reading the pasteboard shows the iOS
247
+ * paste banner — the user-visible, privacy-forward deferred path.)
248
+ */
249
+ declare function resolveClipboardMatch(): Promise<DeepLink | null>;
250
+ interface RNAdvenueConfig extends Omit<AdvenueConfig, 'storage' | 'platform'> {
251
+ /**
252
+ * Auto-detected from React Native's `Platform.OS` — omit it. Pass explicitly
253
+ * only outside a React Native runtime (tests, custom embeddings); `ios` and
254
+ * `android` map verbatim, any other RN target (web, desktop) reports as
255
+ * `web`.
256
+ */
257
+ platform?: AdvenueConfig['platform'];
258
+ /**
259
+ * @internal Storage override (tests / custom embeddings). The SDK persists
260
+ * via its own native modules (UserDefaults/SharedPreferences) — apps never
261
+ * supply storage. When set, it replaces the built-in native storage.
262
+ */
263
+ mmkv?: MMKVLike;
264
+ /**
265
+ * G3.1n — Play Integrity (Android) / App Attest (iOS) attestation.
266
+ *
267
+ * Your app's Advenue appId (the UUID in Settings → API Keys). When set on
268
+ * Android, the automatic install obtains a Play Integrity Standard token and
269
+ * attaches it to the install event. The requestHash is computed as
270
+ * `sha256Hex("<appId>:<deviceId>")`, matching the server's verification
271
+ * formula exactly (see `makeDecodeAndroid` in the worker).
272
+ *
273
+ * Omit to run without attestation (the server field stays `unavailable`).
274
+ */
275
+ appId?: string;
276
+ /**
277
+ * @internal Secure-store override (tests / custom embeddings). The SDK uses
278
+ * its own Keychain-backed native storage on iOS for the reinstall-resilient
279
+ * device identity — apps never supply a secure store. When set, it replaces
280
+ * the built-in Keychain adapter.
281
+ */
282
+ secureStore?: SecureStoreLike;
283
+ /**
284
+ * Unified deep-link callback (AppsFlyer UDL style). Fires for both direct
285
+ * Universal/App Links (the OS opened the app via a link) and deferred deep
286
+ * links (resolved after an attributed install). The SDK never navigates — the
287
+ * host app reads `link.deepLinkValue` and routes. Inspect `link.isDeferred`
288
+ * to distinguish the two. Omit to disable deep-link handling entirely.
289
+ */
290
+ onDeepLink?: (link: DeepLink) => void;
291
+ /**
292
+ * @internal Test hook — disables the automatic install fired by
293
+ * `initialize()`. Install tracking is always automatic in production (there
294
+ * is no public `trackInstall`); tests turn it off to exercise the internal
295
+ * install path deterministically.
296
+ */
297
+ autoTrackInstall?: boolean;
298
+ }
299
+ /**
300
+ * Maps a React Native AppState status to the client's session lifecycle hooks.
301
+ * Exported for testing. 'inactive' (transient on iOS) is intentionally ignored
302
+ * so brief interruptions (Control Center, incoming call) don't end the session.
303
+ */
304
+ declare function applyAppState(client: Pick<AdvenueClient, 'notifyAppActive' | 'notifyAppBackground'>, status: string): void;
305
+ /**
306
+ * React Native entry point. Wires MMKV-backed offline buffering automatically
307
+ * and re-exports the same track surface as the core SDK.
308
+ */
309
+ declare const Advenue: {
310
+ initialize(config: RNAdvenueConfig): Promise<AdvenueClient>;
311
+ track: (name: string, properties?: Record<string, unknown>, opts?: TrackOptions) => void;
312
+ /**
313
+ * Shows the iOS ATT prompt (resolves 'authorized' immediately on Android/web,
314
+ * where ATT doesn't exist) and forwards the result to the consent gate.
315
+ */
316
+ requestTrackingAuthorization(): Promise<TrackingAuthorizationStatus>;
317
+ setTrackingConsent(granted: boolean): void;
318
+ getTrackingConsent: () => boolean;
319
+ /** GDPR/CCPA erasure: stop tracking and wipe local identifiers/queue. */
320
+ forgetMe(): void;
321
+ setConsentData(consent: Consent): void;
322
+ getConsentData: () => {
323
+ isUserSubjectToGDPR: boolean;
324
+ hasConsentForDataUsage?: boolean | undefined;
325
+ hasConsentForAdsPersonalization?: boolean | undefined;
326
+ hasConsentForAdStorage?: boolean | undefined;
327
+ } | null;
328
+ flush: () => Promise<void>;
329
+ getDeviceId: () => string;
330
+ shutdown(): void;
331
+ };
332
+ /**
333
+ * Tracks the install event enriched with native attribution data: Play + Meta
334
+ * install referrers on Android, SKAdNetwork registration on iOS. Fired
335
+ * automatically by `initialize()` (or its consent deferral); when a
336
+ * `secureStore` is wired it fires at most once per device (reinstall-resilient
337
+ * on iOS via Keychain; Android re-fires after a reinstall, which is
338
+ * unavoidable post-GAID).
339
+ *
340
+ * @internal Exported for tests only — install tracking is automatic and this
341
+ * function is deliberately NOT on the `Advenue` facade. Do not call it from
342
+ * app code.
343
+ */
344
+ declare function trackInstall(): Promise<void>;
345
+
346
+ export { Advenue, type AdvenueAndroidNativeModule, type AdvenueDeviceInfo, type AdvenueIosNativeModule, type InstallReferrerResult, type MMKVLike, type MetaInstallReferrerResult, type RNAdvenueConfig, type SecureStoreLike, type TrackingAuthorizationStatus, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, resolveClipboardMatch, trackInstall };
package/dist/index.d.ts CHANGED
@@ -204,10 +204,10 @@ declare function parseDirectLink(url: string): DeepLink;
204
204
 
205
205
  /**
206
206
  * Lazy access to the native modules that ship inside this package (ios/ and
207
- * android/, registered via expo-module.config.json). `requireNativeModule`
208
- * throws when the native side isn't built (Expo Go, web, missing pods), so
209
- * resolution happens inside try/catch — never at module scope.
210
- * expo-modules-core is resolved from the consuming app's Expo install.
207
+ * android/, registered via expo-module.config.json). Host-module resolution
208
+ * goes through native-require.cjs so Metro sees literal requires (see the
209
+ * comment there); `requireNativeModule` throws when the native side isn't
210
+ * built (Expo Go, web, missing pods), so calls stay inside try/catch.
211
211
  */
212
212
  declare function getIosNative(): AdvenueIosNativeModule | null;
213
213
  declare function getAndroidNative(): AdvenueAndroidNativeModule | null;
package/dist/index.js CHANGED
@@ -1,12 +1,69 @@
1
- import { parseInstallReferrer, extractReferrerProperties, parseMetaInstallReferrer } from '@advenue/install-referrer';
2
- import { DEVICE_ID_KEY, DEFAULT_ENDPOINT, MemoryStorage, resolveDurableDeviceId, AdvenueClient } from '@advenue/sdk-core';
3
-
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
7
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
8
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
9
  }) : x)(function(x) {
7
10
  if (typeof require !== "undefined") return require.apply(this, arguments);
8
11
  throw Error('Dynamic require of "' + x + '" is not supported');
9
12
  });
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // src/native-require.cjs
34
+ var require_native_require = __commonJS({
35
+ "src/native-require.cjs"(exports, module) {
36
+ "use strict";
37
+ module.exports.requireExpoModulesCore = function requireExpoModulesCore2() {
38
+ try {
39
+ return __require("expo-modules-core");
40
+ } catch {
41
+ return null;
42
+ }
43
+ };
44
+ module.exports.requireReactNative = function requireReactNative2() {
45
+ try {
46
+ return __require("react-native");
47
+ } catch {
48
+ return null;
49
+ }
50
+ };
51
+ }
52
+ });
53
+
54
+ // src/index.ts
55
+ import {
56
+ extractReferrerProperties,
57
+ parseInstallReferrer,
58
+ parseMetaInstallReferrer
59
+ } from "@advenue/install-referrer";
60
+ import {
61
+ AdvenueClient,
62
+ DEFAULT_ENDPOINT,
63
+ DEVICE_ID_KEY,
64
+ MemoryStorage,
65
+ resolveDurableDeviceId
66
+ } from "@advenue/sdk-core";
10
67
 
11
68
  // ../shared/src/match-token.ts
12
69
  var MATCH_TOKEN_PREFIX = "advmatch:";
@@ -165,6 +222,70 @@ function sha256Hex(message) {
165
222
  return toHex(sha256Bytes(enc.encode(message)));
166
223
  }
167
224
 
225
+ // package.json
226
+ var package_default = {
227
+ name: "@advenue/react-native",
228
+ version: "0.6.2",
229
+ description: "Advenue MMP React Native SDK \u2014 attribution, install tracking, and deep links (bundled iOS/Android Expo native modules)",
230
+ type: "module",
231
+ license: "MIT",
232
+ main: "./dist/index.js",
233
+ types: "./dist/index.d.ts",
234
+ exports: {
235
+ ".": {
236
+ types: "./dist/index.d.ts",
237
+ "react-native": "./dist/index.cjs",
238
+ require: "./dist/index.cjs",
239
+ default: "./dist/index.js"
240
+ },
241
+ "./plugin": "./plugin/index.js"
242
+ },
243
+ files: [
244
+ "dist",
245
+ "src",
246
+ "plugin",
247
+ "scripts",
248
+ "ios",
249
+ "android",
250
+ "expo-module.config.json",
251
+ "!**/*.test.ts"
252
+ ],
253
+ publishConfig: {
254
+ access: "public"
255
+ },
256
+ scripts: {
257
+ build: "tsup && node scripts/check-dist.mjs",
258
+ typecheck: "tsc --noEmit",
259
+ test: "vitest run"
260
+ },
261
+ dependencies: {
262
+ "@advenue/install-referrer": "workspace:*",
263
+ "@advenue/sdk-core": "workspace:*"
264
+ },
265
+ peerDependencies: {
266
+ "@expo/config-plugins": ">=8",
267
+ react: ">=18.2",
268
+ "react-native": ">=0.74",
269
+ "expo-modules-core": "*"
270
+ },
271
+ peerDependenciesMeta: {
272
+ "@expo/config-plugins": {
273
+ optional: true
274
+ },
275
+ "expo-modules-core": {
276
+ optional: true
277
+ }
278
+ },
279
+ devDependencies: {
280
+ "@advenue/shared": "workspace:*",
281
+ "@advenue/signing": "workspace:*",
282
+ tsup: "^8.5.1",
283
+ typescript: "^5.7.2",
284
+ vitest: "^2.1.8"
285
+ },
286
+ "react-native": "./dist/index.cjs"
287
+ };
288
+
168
289
  // src/deep-links.ts
169
290
  function parseDirectLink(url) {
170
291
  let deepLinkValue = "";
@@ -215,39 +336,43 @@ function createMMKVStorage(mmkv) {
215
336
  }
216
337
 
217
338
  // src/native.ts
339
+ var import_native_require = __toESM(require_native_require(), 1);
218
340
  function getIosNative() {
219
341
  try {
220
- const core = __require("expo-modules-core");
221
- return core.requireNativeModule("AdvenueIos");
342
+ const core = (0, import_native_require.requireExpoModulesCore)();
343
+ return core ? core.requireNativeModule("AdvenueIos") : null;
222
344
  } catch {
223
345
  return null;
224
346
  }
225
347
  }
226
348
  function getAndroidNative() {
227
349
  try {
228
- const core = __require("expo-modules-core");
229
- return core.requireNativeModule("AdvenueAndroid");
350
+ const core = (0, import_native_require.requireExpoModulesCore)();
351
+ return core ? core.requireNativeModule("AdvenueAndroid") : null;
230
352
  } catch {
231
353
  return null;
232
354
  }
233
355
  }
234
356
  function getPlatformOS() {
235
357
  try {
236
- return __require("react-native").Platform.OS ?? null;
358
+ const rn = (0, import_native_require.requireReactNative)();
359
+ return rn?.Platform.OS ?? null;
237
360
  } catch {
238
361
  return null;
239
362
  }
240
363
  }
241
364
  function getAppState() {
242
365
  try {
243
- return __require("react-native").AppState;
366
+ const rn = (0, import_native_require.requireReactNative)();
367
+ return rn?.AppState ?? null;
244
368
  } catch {
245
369
  return null;
246
370
  }
247
371
  }
248
372
  function getLinking() {
249
373
  try {
250
- return __require("react-native").Linking;
374
+ const rn = (0, import_native_require.requireReactNative)();
375
+ return rn?.Linking ?? null;
251
376
  } catch {
252
377
  return null;
253
378
  }
@@ -428,6 +553,7 @@ var Advenue = {
428
553
  secureStore = secureMod ? createSecureStore(secureMod) : createNativeSecureStore(iosMod);
429
554
  const deviceId = rest.deviceId ?? await resolveDurableDeviceId(storage, secureStore ?? void 0);
430
555
  instance = new AdvenueClient({ ...rest, platform, deviceId, storage });
556
+ instance.debugLog(`SDK v${package_default.version} \u2014 events -> ${configuredEndpoint}`);
431
557
  void resolveAdvertisingId().catch((err) => reportError("enrich.advertisingId", err));
432
558
  const deviceInfo = collectDeviceInfo({
433
559
  platform,
@@ -680,5 +806,16 @@ async function trackInstall() {
680
806
  }
681
807
  }
682
808
  }
683
-
684
- export { Advenue, applyAppState, collectDeviceInfo, createMMKVStorage, createSecureStore, getAndroidNative, getIosNative, parseDirectLink, resolveAdvertisingId, resolveClipboardMatch, trackInstall };
809
+ export {
810
+ Advenue,
811
+ applyAppState,
812
+ collectDeviceInfo,
813
+ createMMKVStorage,
814
+ createSecureStore,
815
+ getAndroidNative,
816
+ getIosNative,
817
+ parseDirectLink,
818
+ resolveAdvertisingId,
819
+ resolveClipboardMatch,
820
+ trackInstall
821
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@advenue/react-native",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Advenue MMP React Native SDK — attribution, install tracking, and deep links (bundled iOS/Android Expo native modules)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,6 +9,8 @@
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
+ "react-native": "./dist/index.cjs",
13
+ "require": "./dist/index.cjs",
12
14
  "default": "./dist/index.js"
13
15
  },
14
16
  "./plugin": "./plugin/index.js"
@@ -17,6 +19,7 @@
17
19
  "dist",
18
20
  "src",
19
21
  "plugin",
22
+ "scripts",
20
23
  "ios",
21
24
  "android",
22
25
  "expo-module.config.json",
@@ -47,11 +50,12 @@
47
50
  "tsup": "^8.5.1",
48
51
  "typescript": "^5.7.2",
49
52
  "vitest": "^2.1.8",
50
- "@advenue/shared": "0.1.0",
51
- "@advenue/signing": "0.0.0"
53
+ "@advenue/signing": "0.0.0",
54
+ "@advenue/shared": "0.1.0"
52
55
  },
56
+ "react-native": "./dist/index.cjs",
53
57
  "scripts": {
54
- "build": "tsup",
58
+ "build": "tsup && node scripts/check-dist.mjs",
55
59
  "typecheck": "tsc --noEmit",
56
60
  "test": "vitest run"
57
61
  }
@@ -0,0 +1,31 @@
1
+ // Publish guard for the Metro __require regression: the CJS build Metro
2
+ // consumes must keep `require("...")` literals (statically analyzable) and
3
+ // must never contain esbuild's `__require` shim. Runs as part of `pnpm build`
4
+ // so a bad dist can never reach npm again.
5
+ import { readFileSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const cjsPath = fileURLToPath(new URL('../dist/index.cjs', import.meta.url));
9
+ const cjs = readFileSync(cjsPath, 'utf8');
10
+
11
+ const problems = [];
12
+ // Flag __require CALL SITES with a module-string argument (the Metro-invisible
13
+ // shim calls). esbuild's __commonJS helper legitimately names its inner
14
+ // function `__require()` — a definition, not a dynamic require — so a bare
15
+ // name match would false-positive.
16
+ if (/__require\(\s*["']/.test(cjs)) {
17
+ problems.push('dist/index.cjs contains esbuild __require shim calls — Metro cannot resolve them');
18
+ }
19
+ for (const mod of ['expo-modules-core', 'react-native']) {
20
+ // Negative lookbehind: `__require("x")` must NOT satisfy the literal check —
21
+ // that substring trap is exactly how the original regression slipped through.
22
+ if (!new RegExp(String.raw`(?<![\w$])require\((?:"${mod}"|'${mod}')\)`).test(cjs)) {
23
+ problems.push(`dist/index.cjs is missing a genuine literal require("${mod}")`);
24
+ }
25
+ }
26
+
27
+ if (problems.length > 0) {
28
+ console.error(`check-dist failed:\n- ${problems.join('\n- ')}`);
29
+ process.exit(1);
30
+ }
31
+ console.log('check-dist ok: CJS requires are literal, no __require shims');
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  } from '@advenue/sdk-core';
20
20
  import { parseMatchToken } from '@advenue/shared/match-token';
21
21
  import { sha256Hex } from '@advenue/signing';
22
+ import pkg from '../package.json' with { type: 'json' };
22
23
  import { type DeepLinkHandle, setupDeepLinks } from './deep-links';
23
24
  import { type MMKVLike, createMMKVStorage } from './mmkv-storage';
24
25
  import {
@@ -371,6 +372,9 @@ export const Advenue = {
371
372
  const deviceId =
372
373
  rest.deviceId ?? (await resolveDurableDeviceId(storage, secureStore ?? undefined));
373
374
  instance = new AdvenueClient({ ...rest, platform, deviceId, storage });
375
+ // One-line ground truth for "which SDK build talks to which host" — the
376
+ // exact questions a silent integration always raises first.
377
+ instance.debugLog(`SDK v${pkg.version} — events -> ${configuredEndpoint}`);
374
378
  // (a) resolve ad-id at init time
375
379
  void resolveAdvertisingId().catch((err) => reportError('enrich.advertisingId', err));
376
380
  // Collect native device info (Meta CAPI extinfo) once at init time; a