customerio-expo-plugin 3.2.0 → 3.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/package.json +8 -2
- package/plugin/lib/commonjs/helpers/constants/ios.js +76 -8
- package/plugin/lib/commonjs/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/apn/NotificationService.swift +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/apn/PushService.swift +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/fcm/NotificationService.swift +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/fcm/PushService.swift +1 -1
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js +20 -7
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/commonjs/index.js +7 -0
- package/plugin/lib/commonjs/index.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIos.js +17 -0
- package/plugin/lib/commonjs/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js +24 -15
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js +45 -11
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/commonjs/postInstallHelper.js +58 -11
- package/plugin/lib/commonjs/postInstallHelper.js.map +1 -1
- package/plugin/lib/commonjs/types/cio-types.js.map +1 -1
- package/plugin/lib/commonjs/utils/resolveRNSDK.js +97 -0
- package/plugin/lib/commonjs/utils/resolveRNSDK.js.map +1 -0
- package/plugin/lib/commonjs/utils/validation.js +13 -0
- package/plugin/lib/commonjs/utils/validation.js.map +1 -1
- package/plugin/lib/commonjs/utils/writeExpoVersion.js +56 -0
- package/plugin/lib/commonjs/utils/writeExpoVersion.js.map +1 -0
- package/plugin/lib/module/helpers/constants/ios.js +75 -8
- package/plugin/lib/module/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/module/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/lib/module/helpers/native-files/ios/apn/NotificationService.swift +1 -1
- package/plugin/lib/module/helpers/native-files/ios/apn/PushService.swift +1 -1
- package/plugin/lib/module/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/lib/module/helpers/native-files/ios/fcm/NotificationService.swift +1 -1
- package/plugin/lib/module/helpers/native-files/ios/fcm/PushService.swift +1 -1
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js +20 -7
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/module/index.js +7 -0
- package/plugin/lib/module/index.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIos.js +17 -0
- package/plugin/lib/module/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIosSwift.js +24 -15
- package/plugin/lib/module/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js +45 -11
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/module/postInstallHelper.js +58 -11
- package/plugin/lib/module/postInstallHelper.js.map +1 -1
- package/plugin/lib/module/types/cio-types.js.map +1 -1
- package/plugin/lib/module/utils/resolveRNSDK.js +88 -0
- package/plugin/lib/module/utils/resolveRNSDK.js.map +1 -0
- package/plugin/lib/module/utils/validation.js +13 -1
- package/plugin/lib/module/utils/validation.js.map +1 -1
- package/plugin/lib/module/utils/writeExpoVersion.js +48 -0
- package/plugin/lib/module/utils/writeExpoVersion.js.map +1 -0
- package/plugin/lib/typescript/helpers/constants/ios.d.ts +18 -0
- package/plugin/lib/typescript/helpers/utils/injectCIOPodfileCode.d.ts +11 -1
- package/plugin/lib/typescript/types/cio-types.d.ts +7 -0
- package/plugin/lib/typescript/utils/resolveRNSDK.d.ts +7 -0
- package/plugin/lib/typescript/utils/validation.d.ts +3 -2
- package/plugin/lib/typescript/utils/writeExpoVersion.d.ts +3 -0
- package/plugin/src/helpers/constants/ios.ts +87 -8
- package/plugin/src/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/src/helpers/native-files/ios/apn/NotificationService.swift +1 -1
- package/plugin/src/helpers/native-files/ios/apn/PushService.swift +1 -1
- package/plugin/src/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +1 -1
- package/plugin/src/helpers/native-files/ios/fcm/NotificationService.swift +1 -1
- package/plugin/src/helpers/native-files/ios/fcm/PushService.swift +1 -1
- package/plugin/src/helpers/utils/injectCIOPodfileCode.ts +22 -10
- package/plugin/src/index.ts +7 -0
- package/plugin/src/ios/withCIOIos.ts +16 -0
- package/plugin/src/ios/withCIOIosSwift.ts +35 -12
- package/plugin/src/ios/withNotificationsXcodeProject.ts +56 -1
- package/plugin/src/postInstallHelper.js +75 -17
- package/plugin/src/types/cio-types.ts +8 -0
- package/plugin/src/utils/resolveRNSDK.ts +118 -0
- package/plugin/src/utils/validation.ts +18 -1
- package/plugin/src/utils/writeExpoVersion.ts +62 -0
|
@@ -1,20 +1,67 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const RN_SDK_PACKAGE = 'customerio-reactnative';
|
|
4
|
+
|
|
5
|
+
// Locate customerio-reactnative/package.json from a postinstall context.
|
|
6
|
+
//
|
|
7
|
+
// `INIT_CWD` is set by npm, pnpm, and yarn during lifecycle scripts to point
|
|
8
|
+
// at the consumer's project root. That makes it the most reliable starting
|
|
9
|
+
// point — the plugin's own __dirname can be deep inside `.pnpm/...` under pnpm.
|
|
10
|
+
//
|
|
11
|
+
// We probe `${INIT_CWD}/node_modules/customerio-reactnative/package.json` first
|
|
12
|
+
// so we agree with the symlinked layout React Native autolinking expects, then
|
|
13
|
+
// fall back to resolve-from from the consumer root, then to the legacy
|
|
14
|
+
// __dirname-relative walk-up for environments where INIT_CWD is missing.
|
|
15
|
+
function findRNSDKPackageJson() {
|
|
16
|
+
const candidates = [];
|
|
17
|
+
if (process.env.INIT_CWD) {
|
|
18
|
+
candidates.push(path.join(process.env.INIT_CWD, 'node_modules', RN_SDK_PACKAGE, 'package.json'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Legacy flat-npm layout fallback: plugin lives at
|
|
22
|
+
// <consumer>/node_modules/customerio-expo-plugin/plugin/src and the SDK at
|
|
23
|
+
// <consumer>/node_modules/customerio-reactnative.
|
|
24
|
+
candidates.push(path.join(__dirname, '..', '..', '..', RN_SDK_PACKAGE, 'package.json'));
|
|
25
|
+
for (const candidate of candidates) {
|
|
26
|
+
if (fs.existsSync(candidate)) {
|
|
27
|
+
return candidate;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Final fallback: resolve-from from INIT_CWD. This walks up node_modules
|
|
32
|
+
// and handles yarn classic workspaces where the dep is hoisted.
|
|
33
|
+
if (process.env.INIT_CWD) {
|
|
34
|
+
try {
|
|
35
|
+
const resolveFrom = require('resolve-from');
|
|
36
|
+
const resolved = resolveFrom.silent(process.env.INIT_CWD, `${RN_SDK_PACKAGE}/package.json`);
|
|
37
|
+
if (resolved) return resolved;
|
|
38
|
+
} catch (_) {
|
|
39
|
+
// resolve-from missing or unable to resolve — fall through to null.
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
2
44
|
function runPostInstall() {
|
|
3
|
-
|
|
4
|
-
const reactNativePackageJsonFile = `${__dirname}/../../../customerio-reactnative/package.json`;
|
|
5
|
-
const expoPackageJsonFile = `${__dirname}/../../package.json`;
|
|
45
|
+
const expoPackageJsonFile = path.join(__dirname, '..', '..', 'package.json');
|
|
6
46
|
try {
|
|
7
|
-
|
|
8
|
-
if (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
47
|
+
const reactNativePackageJsonFile = findRNSDKPackageJson();
|
|
48
|
+
if (!reactNativePackageJsonFile) {
|
|
49
|
+
// Not necessarily an error: the plugin may be installed without the RN
|
|
50
|
+
// SDK (e.g., during a tooling-only install). The prebuild-time write
|
|
51
|
+
// covers the common case anyway.
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const expoPackageJson = require(expoPackageJsonFile);
|
|
55
|
+
const reactNativePackage = JSON.parse(fs.readFileSync(reactNativePackageJsonFile, 'utf8'));
|
|
56
|
+
if (reactNativePackage.expoVersion === expoPackageJson.version) {
|
|
57
|
+
return;
|
|
14
58
|
}
|
|
59
|
+
reactNativePackage.expoVersion = expoPackageJson.version;
|
|
60
|
+
fs.writeFileSync(reactNativePackageJsonFile, JSON.stringify(reactNativePackage, null, 2));
|
|
15
61
|
} catch (error) {
|
|
16
|
-
console.warn('
|
|
62
|
+
console.warn('customerio-expo-plugin postinstall: failed to write expoVersion into customerio-reactnative/package.json. ' + 'The expo prebuild step will retry this. Original error:', error);
|
|
17
63
|
}
|
|
18
64
|
}
|
|
19
65
|
exports.runPostInstall = runPostInstall;
|
|
66
|
+
exports.findRNSDKPackageJson = findRNSDKPackageJson;
|
|
20
67
|
//# sourceMappingURL=postInstallHelper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["fs","require","
|
|
1
|
+
{"version":3,"names":["fs","require","path","RN_SDK_PACKAGE","findRNSDKPackageJson","candidates","process","env","INIT_CWD","push","join","__dirname","candidate","existsSync","resolveFrom","resolved","silent","_","runPostInstall","expoPackageJsonFile","reactNativePackageJsonFile","expoPackageJson","reactNativePackage","JSON","parse","readFileSync","expoVersion","version","writeFileSync","stringify","error","console","warn","exports"],"sources":["postInstallHelper.js"],"sourcesContent":["const fs = require('fs');\nconst path = require('path');\n\nconst RN_SDK_PACKAGE = 'customerio-reactnative';\n\n// Locate customerio-reactnative/package.json from a postinstall context.\n//\n// `INIT_CWD` is set by npm, pnpm, and yarn during lifecycle scripts to point\n// at the consumer's project root. That makes it the most reliable starting\n// point — the plugin's own __dirname can be deep inside `.pnpm/...` under pnpm.\n//\n// We probe `${INIT_CWD}/node_modules/customerio-reactnative/package.json` first\n// so we agree with the symlinked layout React Native autolinking expects, then\n// fall back to resolve-from from the consumer root, then to the legacy\n// __dirname-relative walk-up for environments where INIT_CWD is missing.\nfunction findRNSDKPackageJson() {\n const candidates = [];\n\n if (process.env.INIT_CWD) {\n candidates.push(\n path.join(process.env.INIT_CWD, 'node_modules', RN_SDK_PACKAGE, 'package.json')\n );\n }\n\n // Legacy flat-npm layout fallback: plugin lives at\n // <consumer>/node_modules/customerio-expo-plugin/plugin/src and the SDK at\n // <consumer>/node_modules/customerio-reactnative.\n candidates.push(path.join(__dirname, '..', '..', '..', RN_SDK_PACKAGE, 'package.json'));\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n\n // Final fallback: resolve-from from INIT_CWD. This walks up node_modules\n // and handles yarn classic workspaces where the dep is hoisted.\n if (process.env.INIT_CWD) {\n try {\n const resolveFrom = require('resolve-from');\n const resolved = resolveFrom.silent(\n process.env.INIT_CWD,\n `${RN_SDK_PACKAGE}/package.json`\n );\n if (resolved) return resolved;\n } catch (_) {\n // resolve-from missing or unable to resolve — fall through to null.\n }\n }\n\n return null;\n}\n\nfunction runPostInstall() {\n const expoPackageJsonFile = path.join(__dirname, '..', '..', 'package.json');\n\n try {\n const reactNativePackageJsonFile = findRNSDKPackageJson();\n if (!reactNativePackageJsonFile) {\n // Not necessarily an error: the plugin may be installed without the RN\n // SDK (e.g., during a tooling-only install). The prebuild-time write\n // covers the common case anyway.\n return;\n }\n\n const expoPackageJson = require(expoPackageJsonFile);\n const reactNativePackage = JSON.parse(\n fs.readFileSync(reactNativePackageJsonFile, 'utf8')\n );\n\n if (reactNativePackage.expoVersion === expoPackageJson.version) {\n return;\n }\n\n reactNativePackage.expoVersion = expoPackageJson.version;\n fs.writeFileSync(\n reactNativePackageJsonFile,\n JSON.stringify(reactNativePackage, null, 2)\n );\n } catch (error) {\n console.warn(\n 'customerio-expo-plugin postinstall: failed to write expoVersion into customerio-reactnative/package.json. ' +\n 'The expo prebuild step will retry this. Original error:',\n error\n );\n }\n}\n\nexports.runPostInstall = runPostInstall;\nexports.findRNSDKPackageJson = findRNSDKPackageJson;\n"],"mappings":"AAAA,MAAMA,EAAE,GAAGC,OAAO,CAAC,IAAI,CAAC;AACxB,MAAMC,IAAI,GAAGD,OAAO,CAAC,MAAM,CAAC;AAE5B,MAAME,cAAc,GAAG,wBAAwB;;AAE/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,oBAAoBA,CAAA,EAAG;EAC9B,MAAMC,UAAU,GAAG,EAAE;EAErB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,EAAE;IACxBH,UAAU,CAACI,IAAI,CACbP,IAAI,CAACQ,IAAI,CAACJ,OAAO,CAACC,GAAG,CAACC,QAAQ,EAAE,cAAc,EAAEL,cAAc,EAAE,cAAc,CAChF,CAAC;EACH;;EAEA;EACA;EACA;EACAE,UAAU,CAACI,IAAI,CAACP,IAAI,CAACQ,IAAI,CAACC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAER,cAAc,EAAE,cAAc,CAAC,CAAC;EAEvF,KAAK,MAAMS,SAAS,IAAIP,UAAU,EAAE;IAClC,IAAIL,EAAE,CAACa,UAAU,CAACD,SAAS,CAAC,EAAE;MAC5B,OAAOA,SAAS;IAClB;EACF;;EAEA;EACA;EACA,IAAIN,OAAO,CAACC,GAAG,CAACC,QAAQ,EAAE;IACxB,IAAI;MACF,MAAMM,WAAW,GAAGb,OAAO,CAAC,cAAc,CAAC;MAC3C,MAAMc,QAAQ,GAAGD,WAAW,CAACE,MAAM,CACjCV,OAAO,CAACC,GAAG,CAACC,QAAQ,EACpB,GAAGL,cAAc,eACnB,CAAC;MACD,IAAIY,QAAQ,EAAE,OAAOA,QAAQ;IAC/B,CAAC,CAAC,OAAOE,CAAC,EAAE;MACV;IAAA;EAEJ;EAEA,OAAO,IAAI;AACb;AAEA,SAASC,cAAcA,CAAA,EAAG;EACxB,MAAMC,mBAAmB,GAAGjB,IAAI,CAACQ,IAAI,CAACC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;EAE5E,IAAI;IACF,MAAMS,0BAA0B,GAAGhB,oBAAoB,CAAC,CAAC;IACzD,IAAI,CAACgB,0BAA0B,EAAE;MAC/B;MACA;MACA;MACA;IACF;IAEA,MAAMC,eAAe,GAAGpB,OAAO,CAACkB,mBAAmB,CAAC;IACpD,MAAMG,kBAAkB,GAAGC,IAAI,CAACC,KAAK,CACnCxB,EAAE,CAACyB,YAAY,CAACL,0BAA0B,EAAE,MAAM,CACpD,CAAC;IAED,IAAIE,kBAAkB,CAACI,WAAW,KAAKL,eAAe,CAACM,OAAO,EAAE;MAC9D;IACF;IAEAL,kBAAkB,CAACI,WAAW,GAAGL,eAAe,CAACM,OAAO;IACxD3B,EAAE,CAAC4B,aAAa,CACdR,0BAA0B,EAC1BG,IAAI,CAACM,SAAS,CAACP,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAC5C,CAAC;EACH,CAAC,CAAC,OAAOQ,KAAK,EAAE;IACdC,OAAO,CAACC,IAAI,CACV,4GAA4G,GAC1G,yDAAyD,EAC3DF,KACF,CAAC;EACH;AACF;AAEAG,OAAO,CAACf,cAAc,GAAGA,cAAc;AACvCe,OAAO,CAAC7B,oBAAoB,GAAGA,oBAAoB","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["cio-types.ts"],"sourcesContent":["/**\n * Properties set by the user in their app config file (e.g: app.json or app.plugin.js)\n * @public\n */\nexport type CustomerIOPluginProperties = {\n // (iOS only) Environment name and bundle identifier\n devTeam: string;\n iosDeploymentTarget: string;\n};\n\n/**\n * Plugin options for iOS platform configuration\n * @public\n */\nexport type CustomerIOPluginOptionsIOS = {\n iosPath: string;\n devTeam?: string;\n bundleVersion?: string;\n bundleShortVersion?: string;\n bundleIdentifier?: string;\n iosDeploymentTarget?: string;\n appleTeamId?: string;\n appName?: string;\n\n useFrameworks?: 'static' | 'dynamic';\n\n pushNotification?: CustomerIOPluginPushNotificationOptions;\n\n /**\n * @deprecated No longer has any effect. Use autoTrackPushEvents to control if push metrics should be automatically tracked by SDK.\n */\n handleNotificationClick?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.autoFetchDeviceToken instead\n */\n autoFetchDeviceToken?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.showPushAppInForeground instead\n */\n showPushAppInForeground?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.autoTrackPushEvents instead\n */\n autoTrackPushEvents?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.handleDeeplinkInKilledState instead\n */\n handleDeeplinkInKilledState?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.disableNotificationRegistration instead\n */\n disableNotificationRegistration?: boolean;\n};\n\n/**\n * Plugin options for Android platform configuration\n * @public\n */\nexport type CustomerIOPluginOptionsAndroid = {\n androidPath: string;\n googleServicesFile?: string;\n setHighPriorityPushHandler?: boolean;\n pushNotification?: {\n channel?: {\n id?: string;\n name?: string;\n importance?: number;\n };\n };\n /**\n * Controls whether to disable Android 16 support by downgrading androidx dependencies.\n *\n * When true (default for Expo SDK 53), forces older androidx versions compatible with\n * Android API 35 and AGP 8.8.2, preventing Android 16 incompatibility errors.\n *\n * When false (default for Expo SDK 54+), allows newer androidx versions that support Android 16\n * but require Android API 36 and AGP 8.9.1+.\n *\n * If not specified, the plugin auto-detects based on Expo SDK version:\n * - Expo SDK ≤53: true (disables Android 16)\n * - Expo SDK ≥54: false (enables Android 16)\n */\n disableAndroid16Support?: boolean;\n};\n\n/**\n * Location tracking mode for the Customer.io SDK location module.\n * Location is off by default. Only used when location is enabled (plugin option location.enabled: true).\n * @public\n */\nexport type LocationTrackingMode = 'OFF' | 'MANUAL' | 'ON_APP_START';\n\n/**\n * SDK configuration options for auto initialization\n * @public\n */\nexport type NativeSDKConfig = {\n cdpApiKey: string; // Required\n region?: 'US' | 'EU'; // Default: 'US'. The workspace region set for your workspace on the Customer.io dashboard\n autoTrackDeviceAttributes?: boolean; // Default: true\n trackApplicationLifecycleEvents?: boolean; // Default: true\n screenViewUse?: 'all' | 'inapp'; // Default: 'all'. 'all': sent to server + in-app messages, 'inapp': in-app messages only\n logLevel?: 'none' | 'error' | 'info' | 'debug'; // Default: 'debug'. Controls SDK logging verbosity\n siteId?: string; // Optional, if only siteId defined, migrationSiteId = siteId\n migrationSiteId?: string; // Optional, if only migrationSiteId defined, siteId should be null\n /**\n * Location module config. Location is off by default; only applied when plugin option location.enabled is true.\n * trackingMode: 'MANUAL' (host app controls when location is captured, default),\n * 'ON_APP_START' (SDK captures once per launch when app becomes active), or 'OFF'.\n */\n location?: {\n trackingMode?: LocationTrackingMode;\n };\n};\n\n/**\n * Location is off by default. When true, enables the Customer.io SDK location native module (iOS Podfile location subspec,\n * Android gradle.properties flag). Permissions and privacy keys (Info.plist, AndroidManifest)\n * remain the host app's responsibility.\n * @public\n */\nexport type CustomerIOPluginLocationOptions = {\n enabled?: boolean;\n};\n\n/**\n * Combined plugin options for both iOS and Android platforms\n * @public\n */\nexport type CustomerIOPluginOptions = {\n config?: NativeSDKConfig; // If defined, enables auto initialization of native SDK\n android: CustomerIOPluginOptionsAndroid;\n ios: CustomerIOPluginOptionsIOS;\n /**\n * Location is off by default. When location.enabled is true, the plugin adds SDK build-time setup (Podfile location subspec,\n * gradle.properties). Host apps must add their own location permissions and privacy usage strings.\n */\n location?: CustomerIOPluginLocationOptions;\n};\n\n/**\n * Rich push configuration used to initialize Notification Service Extension (NSE) on the native side\n * @public\n */\nexport type RichPushConfig = {\n cdpApiKey: string;\n region?: string;\n};\n\n/**\n * Push notification configuration options\n * @public\n */\nexport type CustomerIOPluginPushNotificationOptions = {\n provider?: 'apn' | 'fcm';\n googleServicesFile?: string;\n useRichPush?: boolean;\n autoFetchDeviceToken?: boolean;\n autoTrackPushEvents?: boolean;\n showPushAppInForeground?: boolean;\n disableNotificationRegistration?: boolean;\n handleDeeplinkInKilledState?: boolean;\n\n /**\n * Rich push config should match the values used to initialize SDK in the app.\n * Optional if `config` is provided at the top level.\n */\n env?: RichPushConfig;\n};\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["cio-types.ts"],"sourcesContent":["/**\n * Properties set by the user in their app config file (e.g: app.json or app.plugin.js)\n * @public\n */\nexport type CustomerIOPluginProperties = {\n // (iOS only) Environment name and bundle identifier\n devTeam: string;\n iosDeploymentTarget: string;\n};\n\n/**\n * Plugin options for iOS platform configuration\n * @public\n */\nexport type CustomerIOPluginOptionsIOS = {\n iosPath: string;\n devTeam?: string;\n bundleVersion?: string;\n bundleShortVersion?: string;\n bundleIdentifier?: string;\n iosDeploymentTarget?: string;\n appleTeamId?: string;\n appName?: string;\n\n useFrameworks?: 'static' | 'dynamic';\n\n pushNotification?: CustomerIOPluginPushNotificationOptions;\n\n /**\n * @deprecated No longer has any effect. Use autoTrackPushEvents to control if push metrics should be automatically tracked by SDK.\n */\n handleNotificationClick?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.autoFetchDeviceToken instead\n */\n autoFetchDeviceToken?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.showPushAppInForeground instead\n */\n showPushAppInForeground?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.autoTrackPushEvents instead\n */\n autoTrackPushEvents?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.handleDeeplinkInKilledState instead\n */\n handleDeeplinkInKilledState?: boolean;\n\n /**\n * @deprecated Property will be removed in the future. Use ios.pushNotification.disableNotificationRegistration instead\n */\n disableNotificationRegistration?: boolean;\n};\n\n/**\n * Plugin options for Android platform configuration\n * @public\n */\nexport type CustomerIOPluginOptionsAndroid = {\n androidPath: string;\n googleServicesFile?: string;\n setHighPriorityPushHandler?: boolean;\n pushNotification?: {\n channel?: {\n id?: string;\n name?: string;\n importance?: number;\n };\n };\n /**\n * Controls whether to disable Android 16 support by downgrading androidx dependencies.\n *\n * When true (default for Expo SDK 53), forces older androidx versions compatible with\n * Android API 35 and AGP 8.8.2, preventing Android 16 incompatibility errors.\n *\n * When false (default for Expo SDK 54+), allows newer androidx versions that support Android 16\n * but require Android API 36 and AGP 8.9.1+.\n *\n * If not specified, the plugin auto-detects based on Expo SDK version:\n * - Expo SDK ≤53: true (disables Android 16)\n * - Expo SDK ≥54: false (enables Android 16)\n */\n disableAndroid16Support?: boolean;\n};\n\n/**\n * Location tracking mode for the Customer.io SDK location module.\n * Location is off by default. Only used when location is enabled (plugin option location.enabled: true).\n * @public\n */\nexport type LocationTrackingMode = 'OFF' | 'MANUAL' | 'ON_APP_START';\n\n/**\n * SDK configuration options for auto initialization\n * @public\n */\nexport type NativeSDKConfig = {\n cdpApiKey: string; // Required\n region?: 'US' | 'EU'; // Default: 'US'. The workspace region set for your workspace on the Customer.io dashboard\n autoTrackDeviceAttributes?: boolean; // Default: true\n trackApplicationLifecycleEvents?: boolean; // Default: true\n screenViewUse?: 'all' | 'inapp'; // Default: 'all'. 'all': sent to server + in-app messages, 'inapp': in-app messages only\n logLevel?: 'none' | 'error' | 'info' | 'debug'; // Default: 'debug'. Controls SDK logging verbosity\n siteId?: string; // Optional, if only siteId defined, migrationSiteId = siteId\n migrationSiteId?: string; // Optional, if only migrationSiteId defined, siteId should be null\n /**\n * Location module config. Location is off by default; only applied when plugin option location.enabled is true.\n * trackingMode: 'MANUAL' (host app controls when location is captured, default),\n * 'ON_APP_START' (SDK captures once per launch when app becomes active), or 'OFF'.\n */\n location?: {\n trackingMode?: LocationTrackingMode;\n };\n};\n\n/**\n * Location is off by default. When true, enables the Customer.io SDK location native module (iOS Podfile location subspec,\n * Android gradle.properties flag). Permissions and privacy keys (Info.plist, AndroidManifest)\n * remain the host app's responsibility.\n * @public\n */\nexport type CustomerIOPluginLocationOptions = {\n enabled?: boolean;\n};\n\n/**\n * Combined plugin options for both iOS and Android platforms\n * @public\n */\nexport type CustomerIOPluginOptions = {\n config?: NativeSDKConfig; // If defined, enables auto initialization of native SDK\n android: CustomerIOPluginOptionsAndroid;\n ios: CustomerIOPluginOptionsIOS;\n /**\n * Location is off by default. When location.enabled is true, the plugin adds SDK build-time setup (Podfile location subspec,\n * gradle.properties). Host apps must add their own location permissions and privacy usage strings.\n */\n location?: CustomerIOPluginLocationOptions;\n};\n\n/**\n * Rich push configuration used to initialize Notification Service Extension (NSE) on the native side\n * @public\n */\nexport type RichPushConfig = {\n cdpApiKey: string;\n region?: string;\n};\n\n/**\n * Push notification configuration options\n * @public\n */\nexport type CustomerIOPluginPushNotificationOptions = {\n provider?: 'apn' | 'fcm';\n googleServicesFile?: string;\n useRichPush?: boolean;\n autoFetchDeviceToken?: boolean;\n autoTrackPushEvents?: boolean;\n showPushAppInForeground?: boolean;\n disableNotificationRegistration?: boolean;\n handleDeeplinkInKilledState?: boolean;\n\n /**\n * Rich push config should match the values used to initialize SDK in the app.\n * Optional if `config` is provided at the top level.\n */\n env?: RichPushConfig;\n\n /**\n * iOS App Group identifier shared between the host app and the Notification Service Extension.\n * When set, `.appGroupId(...)` is injected into the MessagingPushConfigBuilder, the identifier\n * is added to the host app entitlements, and an NSE entitlements file is written.\n * When omitted, the native SDK handles group discovery on its own and no entitlements are added.\n */\n appGroupId?: string;\n};\n"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const RN_SDK_PACKAGE = 'customerio-reactnative';
|
|
4
|
+
const REACT_NATIVE_PACKAGE = 'react-native';
|
|
5
|
+
// Reads the installed react-native package's version starting from `fromDir`.
|
|
6
|
+
// Used to decide which autolinking flavor will resolve customerio-reactnative
|
|
7
|
+
// at pod install time, so our :path agrees with what autolinking emits:
|
|
8
|
+
// - RN <0.80 ships @react-native-community/cli, which uses a lexical
|
|
9
|
+
// resolution (no realpath following).
|
|
10
|
+
// - RN >=0.80 routes pod autolinking through expo-modules-autolinking,
|
|
11
|
+
// which realpaths.
|
|
12
|
+
// Returns null if react-native cannot be located or its package.json cannot
|
|
13
|
+
// be read; callers should default to the modern (realpath) behavior in that
|
|
14
|
+
// case since it has been the working path for the last several Expo SDKs.
|
|
15
|
+
export function tryReadRNVersion(fromDir) {
|
|
16
|
+
try {
|
|
17
|
+
const direct = path.join(fromDir, 'node_modules', REACT_NATIVE_PACKAGE, 'package.json');
|
|
18
|
+
if (fs.existsSync(direct)) {
|
|
19
|
+
return readVersion(direct);
|
|
20
|
+
}
|
|
21
|
+
const resolveFrom = require('resolve-from');
|
|
22
|
+
const fallback = resolveFrom.silent(fromDir, `${REACT_NATIVE_PACKAGE}/package.json`);
|
|
23
|
+
if (fallback) {
|
|
24
|
+
return readVersion(fallback);
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// Fall through to null.
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function readVersion(pkgJsonPath) {
|
|
32
|
+
try {
|
|
33
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
34
|
+
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Resolves the customerio-reactnative SDK location starting from `fromDir`.
|
|
41
|
+
//
|
|
42
|
+
// Probe-then-fallback so the result agrees with React Native autolinking
|
|
43
|
+
// across npm flat, pnpm, and yarn-workspace layouts:
|
|
44
|
+
// 1. `fromDir/node_modules/customerio-reactnative/package.json` — preferred.
|
|
45
|
+
// Works for npm flat, pnpm (the symlinked path; we never realpath it),
|
|
46
|
+
// and yarn workspaces with leaf node_modules. Matches what RN
|
|
47
|
+
// autolinking emits for its pod entry, so CocoaPods sees one
|
|
48
|
+
// consistent :path.
|
|
49
|
+
// 2. `resolve-from` walking up from `fromDir` — only used when (1) misses.
|
|
50
|
+
// Handles yarn classic workspaces where the dep is hoisted to a parent
|
|
51
|
+
// node_modules. yarn classic has no symlinks, so the realpath is fine.
|
|
52
|
+
//
|
|
53
|
+
// Returns null if neither finds the package, including the case where
|
|
54
|
+
// `resolve-from` itself can't be required (mirrors tryReadRNVersion's
|
|
55
|
+
// graceful-failure shape so callers can rely on the documented contract).
|
|
56
|
+
export function tryResolveRNSDK(fromDir) {
|
|
57
|
+
try {
|
|
58
|
+
const directPkgJson = path.join(fromDir, 'node_modules', RN_SDK_PACKAGE, 'package.json');
|
|
59
|
+
if (fs.existsSync(directPkgJson)) {
|
|
60
|
+
return {
|
|
61
|
+
packageDir: path.dirname(directPkgJson),
|
|
62
|
+
packageJsonPath: directPkgJson
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const resolveFrom = require('resolve-from');
|
|
66
|
+
const fallbackPkgJson = resolveFrom.silent(fromDir, `${RN_SDK_PACKAGE}/package.json`);
|
|
67
|
+
if (fallbackPkgJson) {
|
|
68
|
+
return {
|
|
69
|
+
packageDir: path.dirname(fallbackPkgJson),
|
|
70
|
+
packageJsonPath: fallbackPkgJson
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// Fall through to null. resolveRNSDK() turns this into a clear
|
|
75
|
+
// "customerio-reactnative was not found" error for the caller.
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Same as tryResolveRNSDK but throws a clear error when the package is missing.
|
|
81
|
+
export function resolveRNSDK(fromDir) {
|
|
82
|
+
const resolved = tryResolveRNSDK(fromDir);
|
|
83
|
+
if (!resolved) {
|
|
84
|
+
throw new Error(`${RN_SDK_PACKAGE} was not found relative to ${fromDir}. ` + `Ensure it is installed in your project (or in a parent workspace's node_modules).`);
|
|
85
|
+
}
|
|
86
|
+
return resolved;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=resolveRNSDK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["fs","path","RN_SDK_PACKAGE","REACT_NATIVE_PACKAGE","tryReadRNVersion","fromDir","direct","join","existsSync","readVersion","resolveFrom","require","fallback","silent","pkgJsonPath","pkg","JSON","parse","readFileSync","version","tryResolveRNSDK","directPkgJson","packageDir","dirname","packageJsonPath","fallbackPkgJson","resolveRNSDK","resolved","Error"],"sources":["resolveRNSDK.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nconst RN_SDK_PACKAGE = 'customerio-reactnative';\nconst REACT_NATIVE_PACKAGE = 'react-native';\n\nexport type ResolvedRNSDK = {\n // Absolute path to the package directory.\n packageDir: string;\n // Absolute path to package.json inside that directory.\n packageJsonPath: string;\n};\n\n// Reads the installed react-native package's version starting from `fromDir`.\n// Used to decide which autolinking flavor will resolve customerio-reactnative\n// at pod install time, so our :path agrees with what autolinking emits:\n// - RN <0.80 ships @react-native-community/cli, which uses a lexical\n// resolution (no realpath following).\n// - RN >=0.80 routes pod autolinking through expo-modules-autolinking,\n// which realpaths.\n// Returns null if react-native cannot be located or its package.json cannot\n// be read; callers should default to the modern (realpath) behavior in that\n// case since it has been the working path for the last several Expo SDKs.\nexport function tryReadRNVersion(fromDir: string): string | null {\n try {\n const direct = path.join(\n fromDir,\n 'node_modules',\n REACT_NATIVE_PACKAGE,\n 'package.json'\n );\n if (fs.existsSync(direct)) {\n return readVersion(direct);\n }\n const resolveFrom = require('resolve-from');\n const fallback = resolveFrom.silent(\n fromDir,\n `${REACT_NATIVE_PACKAGE}/package.json`\n );\n if (fallback) {\n return readVersion(fallback);\n }\n } catch {\n // Fall through to null.\n }\n return null;\n}\n\nfunction readVersion(pkgJsonPath: string): string | null {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));\n return typeof pkg.version === 'string' ? pkg.version : null;\n } catch {\n return null;\n }\n}\n\n// Resolves the customerio-reactnative SDK location starting from `fromDir`.\n//\n// Probe-then-fallback so the result agrees with React Native autolinking\n// across npm flat, pnpm, and yarn-workspace layouts:\n// 1. `fromDir/node_modules/customerio-reactnative/package.json` — preferred.\n// Works for npm flat, pnpm (the symlinked path; we never realpath it),\n// and yarn workspaces with leaf node_modules. Matches what RN\n// autolinking emits for its pod entry, so CocoaPods sees one\n// consistent :path.\n// 2. `resolve-from` walking up from `fromDir` — only used when (1) misses.\n// Handles yarn classic workspaces where the dep is hoisted to a parent\n// node_modules. yarn classic has no symlinks, so the realpath is fine.\n//\n// Returns null if neither finds the package, including the case where\n// `resolve-from` itself can't be required (mirrors tryReadRNVersion's\n// graceful-failure shape so callers can rely on the documented contract).\nexport function tryResolveRNSDK(fromDir: string): ResolvedRNSDK | null {\n try {\n const directPkgJson = path.join(\n fromDir,\n 'node_modules',\n RN_SDK_PACKAGE,\n 'package.json'\n );\n if (fs.existsSync(directPkgJson)) {\n return {\n packageDir: path.dirname(directPkgJson),\n packageJsonPath: directPkgJson,\n };\n }\n\n const resolveFrom = require('resolve-from');\n const fallbackPkgJson = resolveFrom.silent(\n fromDir,\n `${RN_SDK_PACKAGE}/package.json`\n );\n if (fallbackPkgJson) {\n return {\n packageDir: path.dirname(fallbackPkgJson),\n packageJsonPath: fallbackPkgJson,\n };\n }\n } catch {\n // Fall through to null. resolveRNSDK() turns this into a clear\n // \"customerio-reactnative was not found\" error for the caller.\n }\n\n return null;\n}\n\n// Same as tryResolveRNSDK but throws a clear error when the package is missing.\nexport function resolveRNSDK(fromDir: string): ResolvedRNSDK {\n const resolved = tryResolveRNSDK(fromDir);\n if (!resolved) {\n throw new Error(\n `${RN_SDK_PACKAGE} was not found relative to ${fromDir}. ` +\n `Ensure it is installed in your project (or in a parent workspace's node_modules).`\n );\n }\n return resolved;\n}\n"],"mappings":"AAAA,OAAOA,EAAE,MAAM,IAAI;AACnB,OAAOC,IAAI,MAAM,MAAM;AAEvB,MAAMC,cAAc,GAAG,wBAAwB;AAC/C,MAAMC,oBAAoB,GAAG,cAAc;AAS3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAACC,OAAe,EAAiB;EAC/D,IAAI;IACF,MAAMC,MAAM,GAAGL,IAAI,CAACM,IAAI,CACtBF,OAAO,EACP,cAAc,EACdF,oBAAoB,EACpB,cACF,CAAC;IACD,IAAIH,EAAE,CAACQ,UAAU,CAACF,MAAM,CAAC,EAAE;MACzB,OAAOG,WAAW,CAACH,MAAM,CAAC;IAC5B;IACA,MAAMI,WAAW,GAAGC,OAAO,CAAC,cAAc,CAAC;IAC3C,MAAMC,QAAQ,GAAGF,WAAW,CAACG,MAAM,CACjCR,OAAO,EACP,GAAGF,oBAAoB,eACzB,CAAC;IACD,IAAIS,QAAQ,EAAE;MACZ,OAAOH,WAAW,CAACG,QAAQ,CAAC;IAC9B;EACF,CAAC,CAAC,MAAM;IACN;EAAA;EAEF,OAAO,IAAI;AACb;AAEA,SAASH,WAAWA,CAACK,WAAmB,EAAiB;EACvD,IAAI;IACF,MAAMC,GAAG,GAAGC,IAAI,CAACC,KAAK,CAACjB,EAAE,CAACkB,YAAY,CAACJ,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7D,OAAO,OAAOC,GAAG,CAACI,OAAO,KAAK,QAAQ,GAAGJ,GAAG,CAACI,OAAO,GAAG,IAAI;EAC7D,CAAC,CAAC,MAAM;IACN,OAAO,IAAI;EACb;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACf,OAAe,EAAwB;EACrE,IAAI;IACF,MAAMgB,aAAa,GAAGpB,IAAI,CAACM,IAAI,CAC7BF,OAAO,EACP,cAAc,EACdH,cAAc,EACd,cACF,CAAC;IACD,IAAIF,EAAE,CAACQ,UAAU,CAACa,aAAa,CAAC,EAAE;MAChC,OAAO;QACLC,UAAU,EAAErB,IAAI,CAACsB,OAAO,CAACF,aAAa,CAAC;QACvCG,eAAe,EAAEH;MACnB,CAAC;IACH;IAEA,MAAMX,WAAW,GAAGC,OAAO,CAAC,cAAc,CAAC;IAC3C,MAAMc,eAAe,GAAGf,WAAW,CAACG,MAAM,CACxCR,OAAO,EACP,GAAGH,cAAc,eACnB,CAAC;IACD,IAAIuB,eAAe,EAAE;MACnB,OAAO;QACLH,UAAU,EAAErB,IAAI,CAACsB,OAAO,CAACE,eAAe,CAAC;QACzCD,eAAe,EAAEC;MACnB,CAAC;IACH;EACF,CAAC,CAAC,MAAM;IACN;IACA;EAAA;EAGF,OAAO,IAAI;AACb;;AAEA;AACA,OAAO,SAASC,YAAYA,CAACrB,OAAe,EAAiB;EAC3D,MAAMsB,QAAQ,GAAGP,eAAe,CAACf,OAAO,CAAC;EACzC,IAAI,CAACsB,QAAQ,EAAE;IACb,MAAM,IAAIC,KAAK,CACb,GAAG1B,cAAc,8BAA8BG,OAAO,IAAI,GAC1D,mFACF,CAAC;EACH;EACA,OAAOsB,QAAQ;AACjB","ignoreList":[]}
|
|
@@ -76,5 +76,17 @@ function validateRichPushConfig(config) {
|
|
|
76
76
|
isValid = validateRegion(config === null || config === void 0 ? void 0 : config.region, 'region', context) && isValid;
|
|
77
77
|
return isValid;
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
function validatePushNotificationOptions(options) {
|
|
80
|
+
const context = 'PushNotification';
|
|
81
|
+
let isValid = true;
|
|
82
|
+
const appGroupId = options.appGroupId;
|
|
83
|
+
if (appGroupId !== undefined) {
|
|
84
|
+
isValid = validateString(appGroupId, 'appGroupId', context) && isValid;
|
|
85
|
+
if (isValid && !appGroupId.startsWith('group.')) {
|
|
86
|
+
logger.warn(`${context}: appGroupId "${appGroupId}" does not start with "group." — ensure this matches your Apple App Group entitlement.`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return isValid;
|
|
90
|
+
}
|
|
91
|
+
export { validateNativeSDKConfig, validatePushNotificationOptions, validateRequired, validateRichPushConfig, validateString };
|
|
80
92
|
//# sourceMappingURL=validation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["logger","validate","isValid","messageFactory","message","process","env","CUSTOMERIO_STRICT_MODE","Error","format","warn","isUndefined","value","undefined","validateRequired","fieldName","context","validateString","trim","validateBoolean","validateEnum","allowedValues","lowerValue","toLowerCase","lowerAllowedValues","map","v","includes","valuesStr","join","validateRegion","validateNativeSDKConfig","config","cdpApiKey","region","screenViewUse","logLevel","autoTrackDeviceAttributes","trackApplicationLifecycleEvents","siteId","migrationSiteId","validateRichPushConfig"],"sources":["validation.ts"],"sourcesContent":["import type { NativeSDKConfig, RichPushConfig } from '../types/cio-types';\nimport { logger } from './logger';\n\n/**\n * Validates a condition and handles errors based on CUSTOMERIO_STRICT_MODE flag.\n * @param isValid - Function that returns true if validation passes\n * @param messageFactory - Function that returns the error message if validation fails\n * @returns true if validation passes, false if it fails\n */\nfunction validate(isValid: () => boolean, messageFactory: () => string): boolean {\n if (isValid()) {\n return true;\n }\n\n // Throw errors unless explicitly disabled, default to strict validation\n const message = messageFactory();\n // Throw an error if strict mode is enabled, log a warning otherwise\n if (process.env.CUSTOMERIO_STRICT_MODE === 'true') {\n throw new Error(logger.format(message));\n } else {\n logger.warn(message);\n }\n return false;\n}\n\nfunction isUndefined(value: unknown): boolean {\n return value === undefined;\n}\n\nfunction validateRequired(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => !isUndefined(value) && value !== null,\n () => `${context}: ${fieldName} is required, received: ${value}`\n );\n}\n\nfunction validateString(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => isUndefined(value) || (typeof value === 'string' && value.trim() !== ''),\n () => `${context}: ${fieldName} must be a non-empty string, received: ${typeof value === 'string' ? `\"${value}\"` : value}`\n );\n}\n\nfunction validateBoolean(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => isUndefined(value) || typeof value === 'boolean',\n () => `${context}: ${fieldName} must be a boolean, received: ${value}`\n );\n}\n\nfunction validateEnum<T extends string>(\n value: unknown,\n fieldName: string,\n allowedValues: readonly T[],\n context: string\n): boolean {\n if (isUndefined(value)) return true;\n\n // First validate it's a string\n if (!validateString(value, fieldName, context)) {\n return false;\n }\n\n // Then validate it's in the allowed values\n return validate(\n () => {\n const lowerValue = (value as string).toLowerCase();\n const lowerAllowedValues = allowedValues.map(v => v.toLowerCase());\n return lowerAllowedValues.includes(lowerValue);\n },\n () => {\n const valuesStr = allowedValues.map(v => `\"${v}\"`).join(', ');\n return `${context}: ${fieldName} must be one of ${valuesStr}, received: ${value}`;\n }\n );\n}\n\nfunction validateRegion(value: unknown, fieldName: string, context: string): boolean {\n return validateEnum(value, fieldName, ['US', 'EU'], context);\n}\n\nfunction validateNativeSDKConfig(config: NativeSDKConfig): boolean {\n const context = 'NativeSDKConfig';\n\n let isValid = true;\n\n isValid = validateRequired(config.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateString(config.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateRegion(config.region, 'region', context) && isValid;\n isValid = validateEnum(config.screenViewUse, 'screenViewUse', ['all', 'inapp'], context) && isValid;\n isValid = validateEnum(config.logLevel, 'logLevel', ['none', 'error', 'info', 'debug'], context) && isValid;\n isValid = validateBoolean(config.autoTrackDeviceAttributes, 'autoTrackDeviceAttributes', context) && isValid;\n isValid = validateBoolean(config.trackApplicationLifecycleEvents, 'trackApplicationLifecycleEvents', context) && isValid;\n isValid = validateString(config.siteId, 'siteId', context) && isValid;\n isValid = validateString(config.migrationSiteId, 'migrationSiteId', context) && isValid;\n\n return isValid;\n}\n\nfunction validateRichPushConfig(config: RichPushConfig | undefined): boolean {\n const context = 'NotificationServiceExtension';\n\n let isValid = true;\n\n isValid = validateRequired(config?.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateString(config?.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateRegion(config?.region, 'region', context) && isValid;\n\n return isValid;\n}\n\nexport {\n validateNativeSDKConfig,\n validateRequired,\n validateRichPushConfig,\n validateString\n};\n\n"],"mappings":"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
|
|
1
|
+
{"version":3,"names":["logger","validate","isValid","messageFactory","message","process","env","CUSTOMERIO_STRICT_MODE","Error","format","warn","isUndefined","value","undefined","validateRequired","fieldName","context","validateString","trim","validateBoolean","validateEnum","allowedValues","lowerValue","toLowerCase","lowerAllowedValues","map","v","includes","valuesStr","join","validateRegion","validateNativeSDKConfig","config","cdpApiKey","region","screenViewUse","logLevel","autoTrackDeviceAttributes","trackApplicationLifecycleEvents","siteId","migrationSiteId","validateRichPushConfig","validatePushNotificationOptions","options","appGroupId","startsWith"],"sources":["validation.ts"],"sourcesContent":["import type { CustomerIOPluginPushNotificationOptions, NativeSDKConfig, RichPushConfig } from '../types/cio-types';\nimport { logger } from './logger';\n\n/**\n * Validates a condition and handles errors based on CUSTOMERIO_STRICT_MODE flag.\n * @param isValid - Function that returns true if validation passes\n * @param messageFactory - Function that returns the error message if validation fails\n * @returns true if validation passes, false if it fails\n */\nfunction validate(isValid: () => boolean, messageFactory: () => string): boolean {\n if (isValid()) {\n return true;\n }\n\n // Throw errors unless explicitly disabled, default to strict validation\n const message = messageFactory();\n // Throw an error if strict mode is enabled, log a warning otherwise\n if (process.env.CUSTOMERIO_STRICT_MODE === 'true') {\n throw new Error(logger.format(message));\n } else {\n logger.warn(message);\n }\n return false;\n}\n\nfunction isUndefined(value: unknown): boolean {\n return value === undefined;\n}\n\nfunction validateRequired(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => !isUndefined(value) && value !== null,\n () => `${context}: ${fieldName} is required, received: ${value}`\n );\n}\n\nfunction validateString(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => isUndefined(value) || (typeof value === 'string' && value.trim() !== ''),\n () => `${context}: ${fieldName} must be a non-empty string, received: ${typeof value === 'string' ? `\"${value}\"` : value}`\n );\n}\n\nfunction validateBoolean(value: unknown, fieldName: string, context: string): boolean {\n return validate(\n () => isUndefined(value) || typeof value === 'boolean',\n () => `${context}: ${fieldName} must be a boolean, received: ${value}`\n );\n}\n\nfunction validateEnum<T extends string>(\n value: unknown,\n fieldName: string,\n allowedValues: readonly T[],\n context: string\n): boolean {\n if (isUndefined(value)) return true;\n\n // First validate it's a string\n if (!validateString(value, fieldName, context)) {\n return false;\n }\n\n // Then validate it's in the allowed values\n return validate(\n () => {\n const lowerValue = (value as string).toLowerCase();\n const lowerAllowedValues = allowedValues.map(v => v.toLowerCase());\n return lowerAllowedValues.includes(lowerValue);\n },\n () => {\n const valuesStr = allowedValues.map(v => `\"${v}\"`).join(', ');\n return `${context}: ${fieldName} must be one of ${valuesStr}, received: ${value}`;\n }\n );\n}\n\nfunction validateRegion(value: unknown, fieldName: string, context: string): boolean {\n return validateEnum(value, fieldName, ['US', 'EU'], context);\n}\n\nfunction validateNativeSDKConfig(config: NativeSDKConfig): boolean {\n const context = 'NativeSDKConfig';\n\n let isValid = true;\n\n isValid = validateRequired(config.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateString(config.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateRegion(config.region, 'region', context) && isValid;\n isValid = validateEnum(config.screenViewUse, 'screenViewUse', ['all', 'inapp'], context) && isValid;\n isValid = validateEnum(config.logLevel, 'logLevel', ['none', 'error', 'info', 'debug'], context) && isValid;\n isValid = validateBoolean(config.autoTrackDeviceAttributes, 'autoTrackDeviceAttributes', context) && isValid;\n isValid = validateBoolean(config.trackApplicationLifecycleEvents, 'trackApplicationLifecycleEvents', context) && isValid;\n isValid = validateString(config.siteId, 'siteId', context) && isValid;\n isValid = validateString(config.migrationSiteId, 'migrationSiteId', context) && isValid;\n\n return isValid;\n}\n\nfunction validateRichPushConfig(config: RichPushConfig | undefined): boolean {\n const context = 'NotificationServiceExtension';\n\n let isValid = true;\n\n isValid = validateRequired(config?.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateString(config?.cdpApiKey, 'cdpApiKey', context) && isValid;\n isValid = validateRegion(config?.region, 'region', context) && isValid;\n\n return isValid;\n}\n\nfunction validatePushNotificationOptions(options: CustomerIOPluginPushNotificationOptions): boolean {\n const context = 'PushNotification';\n\n let isValid = true;\n\n const appGroupId = options.appGroupId;\n if (appGroupId !== undefined) {\n isValid = validateString(appGroupId, 'appGroupId', context) && isValid;\n if (isValid && !appGroupId.startsWith('group.')) {\n logger.warn(`${context}: appGroupId \"${appGroupId}\" does not start with \"group.\" — ensure this matches your Apple App Group entitlement.`);\n }\n }\n\n return isValid;\n}\n\nexport {\n validateNativeSDKConfig,\n validatePushNotificationOptions,\n validateRequired,\n validateRichPushConfig,\n validateString\n};\n\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { logger } from './logger';
|
|
3
|
+
import { getPluginVersion } from './plugin';
|
|
4
|
+
import { tryResolveRNSDK } from './resolveRNSDK';
|
|
5
|
+
|
|
6
|
+
// Writes the plugin's version into customerio-reactnative/package.json under
|
|
7
|
+
// the `expoVersion` key. The RN SDK reads this at runtime (customerio-cdp.ts)
|
|
8
|
+
// to set its User-Agent `packageSource` to "Expo" instead of "ReactNative".
|
|
9
|
+
//
|
|
10
|
+
// We rely on the postinstall hook (postInstallHelper.js) for the same write
|
|
11
|
+
// at install time, but call this from the plugin entry as a fallback for
|
|
12
|
+
// installs where postinstall does not run cleanly — most notably pnpm
|
|
13
|
+
// monorepos and any CI that uses --ignore-scripts.
|
|
14
|
+
//
|
|
15
|
+
// The write is idempotent: we no-op when the value is already correct.
|
|
16
|
+
export function writeExpoVersion(projectRoot) {
|
|
17
|
+
let resolved;
|
|
18
|
+
try {
|
|
19
|
+
resolved = tryResolveRNSDK(projectRoot);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
logger.warn(`Could not locate customerio-reactnative to write expoVersion. ` + `User-Agent attribution may be incorrect. Original error: ${error}`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!resolved) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const pluginVersion = getPluginVersion();
|
|
29
|
+
const pkg = JSON.parse(fs.readFileSync(resolved.packageJsonPath, 'utf8'));
|
|
30
|
+
if (pkg.expoVersion === pluginVersion) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
pkg.expoVersion = pluginVersion;
|
|
34
|
+
fs.writeFileSync(resolved.packageJsonPath, JSON.stringify(pkg, null, 2));
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.warn(`Failed to write expoVersion into ${resolved.packageJsonPath}. ` + `User-Agent attribution may be incorrect. Original error: ${error}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export const withExpoVersion = config => {
|
|
40
|
+
var _internal;
|
|
41
|
+
// _internal.projectRoot is set by Expo when running through prebuild;
|
|
42
|
+
// fall back to process.cwd() for any path that calls the plugin in
|
|
43
|
+
// a non-prebuild context.
|
|
44
|
+
const projectRoot = ((_internal = config._internal) === null || _internal === void 0 ? void 0 : _internal.projectRoot) || process.cwd();
|
|
45
|
+
writeExpoVersion(projectRoot);
|
|
46
|
+
return config;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=writeExpoVersion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["fs","logger","getPluginVersion","tryResolveRNSDK","writeExpoVersion","projectRoot","resolved","error","warn","pluginVersion","pkg","JSON","parse","readFileSync","packageJsonPath","expoVersion","writeFileSync","stringify","withExpoVersion","config","_internal","process","cwd"],"sources":["writeExpoVersion.ts"],"sourcesContent":["import fs from 'fs';\nimport type { ConfigPlugin } from '@expo/config-plugins';\n\nimport { logger } from './logger';\nimport { getPluginVersion } from './plugin';\nimport { tryResolveRNSDK } from './resolveRNSDK';\n\n// Writes the plugin's version into customerio-reactnative/package.json under\n// the `expoVersion` key. The RN SDK reads this at runtime (customerio-cdp.ts)\n// to set its User-Agent `packageSource` to \"Expo\" instead of \"ReactNative\".\n//\n// We rely on the postinstall hook (postInstallHelper.js) for the same write\n// at install time, but call this from the plugin entry as a fallback for\n// installs where postinstall does not run cleanly — most notably pnpm\n// monorepos and any CI that uses --ignore-scripts.\n//\n// The write is idempotent: we no-op when the value is already correct.\nexport function writeExpoVersion(projectRoot: string): void {\n let resolved;\n try {\n resolved = tryResolveRNSDK(projectRoot);\n } catch (error) {\n logger.warn(\n `Could not locate customerio-reactnative to write expoVersion. ` +\n `User-Agent attribution may be incorrect. Original error: ${error}`\n );\n return;\n }\n\n if (!resolved) {\n return;\n }\n\n try {\n const pluginVersion = getPluginVersion();\n const pkg = JSON.parse(fs.readFileSync(resolved.packageJsonPath, 'utf8'));\n if (pkg.expoVersion === pluginVersion) {\n return;\n }\n pkg.expoVersion = pluginVersion;\n fs.writeFileSync(\n resolved.packageJsonPath,\n JSON.stringify(pkg, null, 2)\n );\n } catch (error) {\n logger.warn(\n `Failed to write expoVersion into ${resolved.packageJsonPath}. ` +\n `User-Agent attribution may be incorrect. Original error: ${error}`\n );\n }\n}\n\nexport const withExpoVersion: ConfigPlugin = (config) => {\n // _internal.projectRoot is set by Expo when running through prebuild;\n // fall back to process.cwd() for any path that calls the plugin in\n // a non-prebuild context.\n const projectRoot =\n (config as unknown as { _internal?: { projectRoot?: string } })._internal?.projectRoot ||\n process.cwd();\n writeExpoVersion(projectRoot);\n return config;\n};\n"],"mappings":"AAAA,OAAOA,EAAE,MAAM,IAAI;AAGnB,SAASC,MAAM,QAAQ,UAAU;AACjC,SAASC,gBAAgB,QAAQ,UAAU;AAC3C,SAASC,eAAe,QAAQ,gBAAgB;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAACC,WAAmB,EAAQ;EAC1D,IAAIC,QAAQ;EACZ,IAAI;IACFA,QAAQ,GAAGH,eAAe,CAACE,WAAW,CAAC;EACzC,CAAC,CAAC,OAAOE,KAAK,EAAE;IACdN,MAAM,CAACO,IAAI,CACT,gEAAgE,GAChE,4DAA4DD,KAAK,EACnE,CAAC;IACD;EACF;EAEA,IAAI,CAACD,QAAQ,EAAE;IACb;EACF;EAEA,IAAI;IACF,MAAMG,aAAa,GAAGP,gBAAgB,CAAC,CAAC;IACxC,MAAMQ,GAAG,GAAGC,IAAI,CAACC,KAAK,CAACZ,EAAE,CAACa,YAAY,CAACP,QAAQ,CAACQ,eAAe,EAAE,MAAM,CAAC,CAAC;IACzE,IAAIJ,GAAG,CAACK,WAAW,KAAKN,aAAa,EAAE;MACrC;IACF;IACAC,GAAG,CAACK,WAAW,GAAGN,aAAa;IAC/BT,EAAE,CAACgB,aAAa,CACdV,QAAQ,CAACQ,eAAe,EACxBH,IAAI,CAACM,SAAS,CAACP,GAAG,EAAE,IAAI,EAAE,CAAC,CAC7B,CAAC;EACH,CAAC,CAAC,OAAOH,KAAK,EAAE;IACdN,MAAM,CAACO,IAAI,CACT,oCAAoCF,QAAQ,CAACQ,eAAe,IAAI,GAChE,4DAA4DP,KAAK,EACnE,CAAC;EACH;AACF;AAEA,OAAO,MAAMW,eAA6B,GAAIC,MAAM,IAAK;EAAA,IAAAC,SAAA;EACvD;EACA;EACA;EACA,MAAMf,WAAW,GACf,EAAAe,SAAA,GAACD,MAAM,CAAyDC,SAAS,cAAAA,SAAA,uBAAzEA,SAAA,CAA2Ef,WAAW,KACtFgB,OAAO,CAACC,GAAG,CAAC,CAAC;EACflB,gBAAgB,CAACC,WAAW,CAAC;EAC7B,OAAOc,MAAM;AACf,CAAC","ignoreList":[]}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the relative path from the iOS project dir to the installed
|
|
3
|
+
* customerio-reactnative directory, in the exact form React Native pod
|
|
4
|
+
* autolinking will emit for the same package. The two autolinking
|
|
5
|
+
* flavors disagree on path shape under pnpm/yarn symlinks:
|
|
6
|
+
*
|
|
7
|
+
* - RN <0.80 (`@react-native-community/cli`): walks node_modules
|
|
8
|
+
* lexically, preserves symlinks. We keep the symlink path too —
|
|
9
|
+
* `tryResolveRNSDK` already does this without calling realpath.
|
|
10
|
+
*
|
|
11
|
+
* - RN >=0.80 (`expo-modules-autolinking`): realpaths the package
|
|
12
|
+
* via Node, emitting the underlying `.pnpm/...` (or yarn-classic)
|
|
13
|
+
* path. We match by realpath'ing the resolved directory.
|
|
14
|
+
*
|
|
15
|
+
* Decision points are logged so a customer's prebuild output is enough
|
|
16
|
+
* to triage path-resolution issues without a follow-up "set
|
|
17
|
+
* CUSTOMERIO_DEBUG_MODE and rerun" round-trip.
|
|
18
|
+
*/
|
|
1
19
|
export declare function getRelativePathToRNSDK(iosPath: string): any;
|
|
2
20
|
export declare const IOS_DEPLOYMENT_TARGET = "13.0";
|
|
3
21
|
export declare const GROUP_IDENTIFIER_TEMPLATE_REGEX: RegExp;
|
|
@@ -5,7 +5,17 @@ export type InjectCIOPodfileOptions = {
|
|
|
5
5
|
/** When false and locationEnabled, inject only :subspecs => ['location']. When true, use push + location. */
|
|
6
6
|
hasPush?: boolean;
|
|
7
7
|
};
|
|
8
|
-
/** Builds the host
|
|
8
|
+
/** Builds the host-app pod snippet for the Podfile.
|
|
9
|
+
*
|
|
10
|
+
* The :path is resolved at prebuild time by `getRelativePathToRNSDK`,
|
|
11
|
+
* which dispatches on the installed React Native version so the path
|
|
12
|
+
* matches what RN pod autolinking will emit (lexical for RN <0.80,
|
|
13
|
+
* realpath for RN >=0.80). Baking the resolved string directly avoids
|
|
14
|
+
* any Ruby/install-time logic in the Podfile and keeps the snippet
|
|
15
|
+
* trivially diff-able.
|
|
16
|
+
*
|
|
17
|
+
* Exported for tests.
|
|
18
|
+
*/
|
|
9
19
|
export declare function buildHostAppPodSnippet(iosPath: string, isFcmPushProvider: boolean, options?: InjectCIOPodfileOptions): string;
|
|
10
20
|
export declare function injectCIOPodfileCode(iosPath: string, isFcmPushProvider: boolean, options?: InjectCIOPodfileOptions): Promise<void>;
|
|
11
21
|
export declare function injectCIONotificationPodfileCode(iosPath: string, useFrameworks: CustomerIOPluginOptionsIOS['useFrameworks'], isFcmPushProvider: boolean): Promise<void>;
|
|
@@ -153,4 +153,11 @@ export type CustomerIOPluginPushNotificationOptions = {
|
|
|
153
153
|
* Optional if `config` is provided at the top level.
|
|
154
154
|
*/
|
|
155
155
|
env?: RichPushConfig;
|
|
156
|
+
/**
|
|
157
|
+
* iOS App Group identifier shared between the host app and the Notification Service Extension.
|
|
158
|
+
* When set, `.appGroupId(...)` is injected into the MessagingPushConfigBuilder, the identifier
|
|
159
|
+
* is added to the host app entitlements, and an NSE entitlements file is written.
|
|
160
|
+
* When omitted, the native SDK handles group discovery on its own and no entitlements are added.
|
|
161
|
+
*/
|
|
162
|
+
appGroupId?: string;
|
|
156
163
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ResolvedRNSDK = {
|
|
2
|
+
packageDir: string;
|
|
3
|
+
packageJsonPath: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function tryReadRNVersion(fromDir: string): string | null;
|
|
6
|
+
export declare function tryResolveRNSDK(fromDir: string): ResolvedRNSDK | null;
|
|
7
|
+
export declare function resolveRNSDK(fromDir: string): ResolvedRNSDK;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { NativeSDKConfig, RichPushConfig } from '../types/cio-types';
|
|
1
|
+
import type { CustomerIOPluginPushNotificationOptions, NativeSDKConfig, RichPushConfig } from '../types/cio-types';
|
|
2
2
|
declare function validateRequired(value: unknown, fieldName: string, context: string): boolean;
|
|
3
3
|
declare function validateString(value: unknown, fieldName: string, context: string): boolean;
|
|
4
4
|
declare function validateNativeSDKConfig(config: NativeSDKConfig): boolean;
|
|
5
5
|
declare function validateRichPushConfig(config: RichPushConfig | undefined): boolean;
|
|
6
|
-
|
|
6
|
+
declare function validatePushNotificationOptions(options: CustomerIOPluginPushNotificationOptions): boolean;
|
|
7
|
+
export { validateNativeSDKConfig, validatePushNotificationOptions, validateRequired, validateRichPushConfig, validateString };
|
|
@@ -1,18 +1,97 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import * as semver from 'semver';
|
|
3
|
+
|
|
1
4
|
const path = require('path');
|
|
2
|
-
|
|
5
|
+
import { resolveRNSDK, tryReadRNVersion } from '../../utils/resolveRNSDK';
|
|
6
|
+
|
|
7
|
+
// Threshold at which React Native pod autolinking moves from
|
|
8
|
+
// @react-native-community/cli (lexical, symlink-preserving) to
|
|
9
|
+
// expo-modules-autolinking (realpath). The two flavors emit different
|
|
10
|
+
// :path strings on pnpm/yarn-symlink layouts, so to keep CocoaPods happy
|
|
11
|
+
// we must match whichever flavor will resolve the same package later.
|
|
12
|
+
const RN_REALPATH_AUTOLINKING_MIN_VERSION = '0.80.0';
|
|
13
|
+
|
|
14
|
+
const PLUGIN_LOG_PREFIX = '[CustomerIO Plugin]';
|
|
15
|
+
|
|
16
|
+
// Always-on so the trail shows up in customer-shared `expo prebuild`
|
|
17
|
+
// output without needing a separate verbose-mode opt-in.
|
|
18
|
+
function pluginLog(message: string): void {
|
|
19
|
+
// eslint-disable-next-line no-console
|
|
20
|
+
console.log(`${PLUGIN_LOG_PREFIX} ${message}`);
|
|
21
|
+
}
|
|
3
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Returns the relative path from the iOS project dir to the installed
|
|
25
|
+
* customerio-reactnative directory, in the exact form React Native pod
|
|
26
|
+
* autolinking will emit for the same package. The two autolinking
|
|
27
|
+
* flavors disagree on path shape under pnpm/yarn symlinks:
|
|
28
|
+
*
|
|
29
|
+
* - RN <0.80 (`@react-native-community/cli`): walks node_modules
|
|
30
|
+
* lexically, preserves symlinks. We keep the symlink path too —
|
|
31
|
+
* `tryResolveRNSDK` already does this without calling realpath.
|
|
32
|
+
*
|
|
33
|
+
* - RN >=0.80 (`expo-modules-autolinking`): realpaths the package
|
|
34
|
+
* via Node, emitting the underlying `.pnpm/...` (or yarn-classic)
|
|
35
|
+
* path. We match by realpath'ing the resolved directory.
|
|
36
|
+
*
|
|
37
|
+
* Decision points are logged so a customer's prebuild output is enough
|
|
38
|
+
* to triage path-resolution issues without a follow-up "set
|
|
39
|
+
* CUSTOMERIO_DEBUG_MODE and rerun" round-trip.
|
|
40
|
+
*/
|
|
4
41
|
export function getRelativePathToRNSDK(iosPath: string) {
|
|
5
|
-
// Root path of the Expo project
|
|
6
42
|
const rootAppPath = path.dirname(iosPath);
|
|
43
|
+
pluginLog(
|
|
44
|
+
`Resolving customerio-reactnative for Podfile (iosPath=${iosPath}, projectRoot=${rootAppPath})`
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const { packageDir } = resolveRNSDK(rootAppPath);
|
|
48
|
+
pluginLog(`customerio-reactnative resolved to: ${packageDir}`);
|
|
7
49
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
50
|
+
const rnVersion = tryReadRNVersion(rootAppPath);
|
|
51
|
+
pluginLog(`Detected react-native version: ${rnVersion ?? 'unknown'}`);
|
|
52
|
+
|
|
53
|
+
const useLexical = shouldUseLexicalPath(rnVersion);
|
|
54
|
+
pluginLog(
|
|
55
|
+
useLexical
|
|
56
|
+
? `RN <${RN_REALPATH_AUTOLINKING_MIN_VERSION} — using lexical/symlink path to match @react-native-community/cli autolinking`
|
|
57
|
+
: `RN >=${RN_REALPATH_AUTOLINKING_MIN_VERSION} or unknown — using realpath to match expo-modules-autolinking`
|
|
12
58
|
);
|
|
13
59
|
|
|
14
|
-
|
|
15
|
-
|
|
60
|
+
let absolutePath: string;
|
|
61
|
+
if (useLexical) {
|
|
62
|
+
absolutePath = packageDir;
|
|
63
|
+
} else {
|
|
64
|
+
try {
|
|
65
|
+
absolutePath = fs.realpathSync(packageDir);
|
|
66
|
+
if (absolutePath !== packageDir) {
|
|
67
|
+
pluginLog(`Realpath differs from resolved dir: ${absolutePath}`);
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
pluginLog(
|
|
71
|
+
`realpathSync failed (${
|
|
72
|
+
err instanceof Error ? err.message : String(err)
|
|
73
|
+
}); falling back to symlink path`
|
|
74
|
+
);
|
|
75
|
+
absolutePath = packageDir;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const relativePath = path.relative(iosPath, absolutePath);
|
|
80
|
+
pluginLog(`Final Podfile :path => '${relativePath}'`);
|
|
81
|
+
return relativePath;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function shouldUseLexicalPath(rnVersion: string | null): boolean {
|
|
85
|
+
if (!rnVersion) {
|
|
86
|
+
// Modern Expo (realpath) has been the working path for the last few
|
|
87
|
+
// SDKs, so it's the safer default when RN can't be detected.
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const coerced = semver.valid(rnVersion) || semver.coerce(rnVersion);
|
|
91
|
+
if (!coerced) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return semver.lt(coerced, RN_REALPATH_AUTOLINKING_MIN_VERSION);
|
|
16
95
|
}
|
|
17
96
|
|
|
18
97
|
export const IOS_DEPLOYMENT_TARGET = '13.0';
|
|
@@ -42,7 +42,7 @@ public class CioSdkAppDelegateHandler: NSObject {
|
|
|
42
42
|
MessagingPushAPN.initialize(
|
|
43
43
|
withConfig: MessagingPushConfigBuilder()
|
|
44
44
|
.autoFetchDeviceToken({{AUTO_FETCH_DEVICE_TOKEN}})
|
|
45
|
-
.showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
45
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
46
46
|
.autoTrackPushEvents({{AUTO_TRACK_PUSH_EVENTS}})
|
|
47
47
|
.build()
|
|
48
48
|
)
|
|
@@ -12,7 +12,7 @@ public class NotificationServiceCioManager : NSObject {
|
|
|
12
12
|
MessagingPushAPN.initializeForExtension(
|
|
13
13
|
withConfig: MessagingPushConfigBuilder(cdpApiKey: Env.customerIOCdpApiKey)
|
|
14
14
|
.region(Env.customerIORegion)
|
|
15
|
-
.build()
|
|
15
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .build()
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
|
|
@@ -15,7 +15,7 @@ public class CIOAppPushNotificationsHandler : NSObject {
|
|
|
15
15
|
MessagingPushAPN.initialize(
|
|
16
16
|
withConfig: MessagingPushConfigBuilder()
|
|
17
17
|
.autoFetchDeviceToken({{AUTO_FETCH_DEVICE_TOKEN}})
|
|
18
|
-
.showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
18
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
19
19
|
.autoTrackPushEvents({{AUTO_TRACK_PUSH_EVENTS}})
|
|
20
20
|
.build()
|
|
21
21
|
)
|
|
@@ -52,7 +52,7 @@ public class CioSdkAppDelegateHandler: NSObject {
|
|
|
52
52
|
MessagingPushFCM.initialize(
|
|
53
53
|
withConfig: MessagingPushConfigBuilder()
|
|
54
54
|
.autoFetchDeviceToken({{AUTO_FETCH_DEVICE_TOKEN}})
|
|
55
|
-
.showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
55
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
56
56
|
.autoTrackPushEvents({{AUTO_TRACK_PUSH_EVENTS}})
|
|
57
57
|
.build()
|
|
58
58
|
)
|
|
@@ -12,7 +12,7 @@ public class NotificationServiceCioManager : NSObject {
|
|
|
12
12
|
MessagingPushFCM.initializeForExtension(
|
|
13
13
|
withConfig: MessagingPushConfigBuilder(cdpApiKey: Env.customerIOCdpApiKey)
|
|
14
14
|
.region(Env.customerIORegion)
|
|
15
|
-
.build()
|
|
15
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .build()
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
MessagingPush.shared.didReceive(request, withContentHandler: contentHandler)
|
|
@@ -23,7 +23,7 @@ public class CIOAppPushNotificationsHandler : NSObject {
|
|
|
23
23
|
MessagingPushFCM.initialize(
|
|
24
24
|
withConfig: MessagingPushConfigBuilder()
|
|
25
25
|
.autoFetchDeviceToken({{AUTO_FETCH_DEVICE_TOKEN}})
|
|
26
|
-
.showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
26
|
+
{{APP_GROUP_ID_BUILDER_LINE}} .showPushAppInForeground({{SHOW_PUSH_APP_IN_FOREGROUND}})
|
|
27
27
|
.autoTrackPushEvents({{AUTO_TRACK_PUSH_EVENTS}})
|
|
28
28
|
.build()
|
|
29
29
|
)
|