@luciq/react-native 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/FONTS_SETUP_GUIDE.md +521 -0
  3. package/Gemfile +1 -0
  4. package/Gemfile.lock +11 -0
  5. package/LICENSE +21 -0
  6. package/README.md +148 -0
  7. package/RNLuciq.podspec +21 -0
  8. package/android/build.gradle +88 -0
  9. package/android/gradle.properties +4 -0
  10. package/android/jacoco.gradle +52 -0
  11. package/android/native.gradle +7 -0
  12. package/android/proguard-rules.txt +1 -0
  13. package/android/sourcemaps.gradle +255 -0
  14. package/android/src/main/AndroidManifest.xml +4 -0
  15. package/android/src/main/java/ai/luciq/reactlibrary/ArgsRegistry.java +278 -0
  16. package/android/src/main/java/ai/luciq/reactlibrary/Constants.java +20 -0
  17. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciq.java +328 -0
  18. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqAPMModule.java +392 -0
  19. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqBugReportingModule.java +444 -0
  20. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqCrashReportingModule.java +169 -0
  21. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqFeatureRequestsModule.java +98 -0
  22. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqNetworkLoggerModule.java +195 -0
  23. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativeModule.java +1611 -0
  24. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativePackage.java +41 -0
  25. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqRepliesModule.java +298 -0
  26. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqSessionReplayModule.java +213 -0
  27. package/android/src/main/java/ai/luciq/reactlibrary/RNLuciqSurveysModule.java +237 -0
  28. package/android/src/main/java/ai/luciq/reactlibrary/utils/ArrayUtil.java +167 -0
  29. package/android/src/main/java/ai/luciq/reactlibrary/utils/EventEmitterModule.java +35 -0
  30. package/android/src/main/java/ai/luciq/reactlibrary/utils/LuciqUtil.java +58 -0
  31. package/android/src/main/java/ai/luciq/reactlibrary/utils/MainThreadHandler.java +13 -0
  32. package/android/src/main/java/ai/luciq/reactlibrary/utils/MapUtil.java +171 -0
  33. package/android/src/main/java/ai/luciq/reactlibrary/utils/RNTouchedViewExtractor.java +167 -0
  34. package/android/src/main/java/ai/luciq/reactlibrary/utils/ReportUtil.java +67 -0
  35. package/app.plugin.js +1 -0
  36. package/babel.config.js +3 -0
  37. package/bin/commands/MigrateCommand.d.ts +6 -0
  38. package/bin/commands/UploadEasUpdatesSourcemaps.d.ts +2 -0
  39. package/bin/commands/UploadSoFiles.d.ts +6 -0
  40. package/bin/commands/UploadSourcemaps.d.ts +2 -0
  41. package/bin/config/migration-config.json +125 -0
  42. package/bin/index.d.ts +2 -0
  43. package/bin/index.js +19179 -0
  44. package/bin/upload/index.d.ts +4 -0
  45. package/bin/upload/migrate.d.ts +14 -0
  46. package/bin/upload/uploadEasUpdatesSourcemaps.d.ts +21 -0
  47. package/bin/upload/uploadSoFiles.d.ts +21 -0
  48. package/bin/upload/uploadSourcemaps.d.ts +21 -0
  49. package/cli/commands/MigrateCommand.ts +32 -0
  50. package/cli/commands/UploadEasUpdatesSourcemaps.ts +34 -0
  51. package/cli/commands/UploadSoFiles.ts +38 -0
  52. package/cli/commands/UploadSourcemaps.ts +40 -0
  53. package/cli/config/migration-config.json +125 -0
  54. package/cli/index.ts +21 -0
  55. package/cli/upload/index.ts +4 -0
  56. package/cli/upload/migrate.ts +271 -0
  57. package/cli/upload/uploadEasUpdatesSourcemaps.ts +74 -0
  58. package/cli/upload/uploadSoFiles.ts +112 -0
  59. package/cli/upload/uploadSourcemaps.ts +73 -0
  60. package/dangerfile.ts +44 -0
  61. package/dist/index.d.ts +19 -0
  62. package/dist/index.js +14 -0
  63. package/dist/models/FeatureFlag.d.ts +11 -0
  64. package/dist/models/FeatureFlag.js +1 -0
  65. package/dist/models/LuciqConfig.d.ts +42 -0
  66. package/dist/models/LuciqConfig.js +1 -0
  67. package/dist/models/NonFatalOptions.d.ts +15 -0
  68. package/dist/models/NonFatalOptions.js +1 -0
  69. package/dist/models/OverAirUpdate.d.ts +12 -0
  70. package/dist/models/OverAirUpdate.js +1 -0
  71. package/dist/models/Report.d.ts +70 -0
  72. package/dist/models/Report.js +109 -0
  73. package/dist/models/ReproConfig.d.ts +27 -0
  74. package/dist/models/ReproConfig.js +1 -0
  75. package/dist/models/SessionMetadata.d.ts +55 -0
  76. package/dist/models/SessionMetadata.js +1 -0
  77. package/dist/models/ThemeConfig.d.ts +27 -0
  78. package/dist/models/ThemeConfig.js +1 -0
  79. package/dist/models/W3cExternalTraceAttributes.d.ts +22 -0
  80. package/dist/models/W3cExternalTraceAttributes.js +1 -0
  81. package/dist/modules/APM.d.ts +77 -0
  82. package/dist/modules/APM.js +104 -0
  83. package/dist/modules/BugReporting.d.ts +138 -0
  84. package/dist/modules/BugReporting.js +202 -0
  85. package/dist/modules/CrashReporting.d.ts +19 -0
  86. package/dist/modules/CrashReporting.js +40 -0
  87. package/dist/modules/FeatureRequests.d.ts +20 -0
  88. package/dist/modules/FeatureRequests.js +28 -0
  89. package/dist/modules/Luciq.d.ts +362 -0
  90. package/dist/modules/Luciq.js +797 -0
  91. package/dist/modules/NetworkLogger.d.ts +52 -0
  92. package/dist/modules/NetworkLogger.js +208 -0
  93. package/dist/modules/Replies.d.ts +78 -0
  94. package/dist/modules/Replies.js +121 -0
  95. package/dist/modules/SessionReplay.d.ts +78 -0
  96. package/dist/modules/SessionReplay.js +98 -0
  97. package/dist/modules/Surveys.d.ts +75 -0
  98. package/dist/modules/Surveys.js +101 -0
  99. package/dist/native/NativeAPM.d.ts +18 -0
  100. package/dist/native/NativeAPM.js +4 -0
  101. package/dist/native/NativeBugReporting.d.ts +32 -0
  102. package/dist/native/NativeBugReporting.js +10 -0
  103. package/dist/native/NativeConstants.d.ts +182 -0
  104. package/dist/native/NativeConstants.js +1 -0
  105. package/dist/native/NativeCrashReporting.d.ts +18 -0
  106. package/dist/native/NativeCrashReporting.js +2 -0
  107. package/dist/native/NativeFeatureRequests.d.ts +8 -0
  108. package/dist/native/NativeFeatureRequests.js +2 -0
  109. package/dist/native/NativeLuciq.d.ts +86 -0
  110. package/dist/native/NativeLuciq.js +10 -0
  111. package/dist/native/NativeNetworkLogger.d.ts +21 -0
  112. package/dist/native/NativeNetworkLogger.js +14 -0
  113. package/dist/native/NativePackage.d.ts +21 -0
  114. package/dist/native/NativePackage.js +2 -0
  115. package/dist/native/NativeReplies.d.ts +21 -0
  116. package/dist/native/NativeReplies.js +8 -0
  117. package/dist/native/NativeSessionReplay.d.ts +16 -0
  118. package/dist/native/NativeSessionReplay.js +8 -0
  119. package/dist/native/NativeSurveys.d.ts +22 -0
  120. package/dist/native/NativeSurveys.js +9 -0
  121. package/dist/utils/AppStatesHandler.d.ts +3 -0
  122. package/dist/utils/AppStatesHandler.js +16 -0
  123. package/dist/utils/Enums.d.ts +244 -0
  124. package/dist/utils/Enums.js +266 -0
  125. package/dist/utils/FeatureFlags.d.ts +7 -0
  126. package/dist/utils/FeatureFlags.js +24 -0
  127. package/dist/utils/LuciqConstants.d.ts +14 -0
  128. package/dist/utils/LuciqConstants.js +15 -0
  129. package/dist/utils/LuciqUtils.d.ts +97 -0
  130. package/dist/utils/LuciqUtils.js +301 -0
  131. package/dist/utils/UnhandledRejectionTracking.d.ts +9 -0
  132. package/dist/utils/UnhandledRejectionTracking.js +99 -0
  133. package/dist/utils/XhrNetworkInterceptor.d.ts +39 -0
  134. package/dist/utils/XhrNetworkInterceptor.js +253 -0
  135. package/dist/utils/config.d.ts +5 -0
  136. package/dist/utils/config.js +6 -0
  137. package/dist/utils/logger.d.ts +10 -0
  138. package/dist/utils/logger.js +39 -0
  139. package/expo.d.ts +1 -0
  140. package/expo.js +1 -0
  141. package/ios/RNLuciq/ArgsRegistry.h +32 -0
  142. package/ios/RNLuciq/ArgsRegistry.m +276 -0
  143. package/ios/RNLuciq/LuciqAPMBridge.h +26 -0
  144. package/ios/RNLuciq/LuciqAPMBridge.m +99 -0
  145. package/ios/RNLuciq/LuciqBugReportingBridge.h +60 -0
  146. package/ios/RNLuciq/LuciqBugReportingBridge.m +241 -0
  147. package/ios/RNLuciq/LuciqCrashReportingBridge.h +18 -0
  148. package/ios/RNLuciq/LuciqCrashReportingBridge.m +68 -0
  149. package/ios/RNLuciq/LuciqFeatureRequestsBridge.h +30 -0
  150. package/ios/RNLuciq/LuciqFeatureRequestsBridge.m +61 -0
  151. package/ios/RNLuciq/LuciqNetworkLoggerBridge.h +44 -0
  152. package/ios/RNLuciq/LuciqNetworkLoggerBridge.m +206 -0
  153. package/ios/RNLuciq/LuciqReactBridge.h +151 -0
  154. package/ios/RNLuciq/LuciqReactBridge.m +548 -0
  155. package/ios/RNLuciq/LuciqRepliesBridge.h +40 -0
  156. package/ios/RNLuciq/LuciqRepliesBridge.m +80 -0
  157. package/ios/RNLuciq/LuciqSessionReplayBridge.h +32 -0
  158. package/ios/RNLuciq/LuciqSessionReplayBridge.m +107 -0
  159. package/ios/RNLuciq/LuciqSurveysBridge.h +46 -0
  160. package/ios/RNLuciq/LuciqSurveysBridge.m +107 -0
  161. package/ios/RNLuciq/RCTConvert+LuciqEnums.h +18 -0
  162. package/ios/RNLuciq/RCTConvert+LuciqEnums.m +127 -0
  163. package/ios/RNLuciq/RNLuciq.h +35 -0
  164. package/ios/RNLuciq/RNLuciq.m +107 -0
  165. package/ios/RNLuciq/Util/LCQAPM+PrivateAPIs.h +15 -0
  166. package/ios/RNLuciq/Util/LCQCrashReporting+CP.h +13 -0
  167. package/ios/RNLuciq/Util/LCQNetworkLogger+CP.h +68 -0
  168. package/ios/RNLuciq/Util/Luciq+CP.h +12 -0
  169. package/ios/RNLuciq.xcodeproj/project.pbxproj +352 -0
  170. package/ios/native.rb +12 -0
  171. package/ios/sourcemaps.sh +120 -0
  172. package/migrate.js +569 -0
  173. package/package.json +92 -0
  174. package/plugin/build/index.js +42078 -0
  175. package/plugin/src/index.ts +5 -0
  176. package/plugin/src/pluginProps.ts +6 -0
  177. package/plugin/src/withLuciq.ts +51 -0
  178. package/plugin/src/withLuciqAndroid.ts +99 -0
  179. package/plugin/src/withLuciqIOS.ts +109 -0
  180. package/plugin/tsconfig.json +7 -0
  181. package/react-native.config.js +16 -0
  182. package/scripts/customize-ios-endpoints.sh +28 -0
  183. package/scripts/dream-11-delete-unused-features.sh +62 -0
  184. package/scripts/find-token.js +58 -0
  185. package/scripts/find-token.sh +70 -0
  186. package/scripts/notify-github.sh +15 -0
  187. package/scripts/replace.js +58 -0
  188. package/scripts/snapshot-comment.md +15 -0
  189. package/scripts/snapshot-version.sh +11 -0
  190. package/src/index.ts +40 -0
  191. package/src/models/FeatureFlag.ts +12 -0
  192. package/src/models/LuciqConfig.ts +48 -0
  193. package/src/models/NonFatalOptions.ts +16 -0
  194. package/src/models/OverAirUpdate.ts +14 -0
  195. package/src/models/Report.ts +124 -0
  196. package/src/models/ReproConfig.ts +31 -0
  197. package/src/models/SessionMetadata.ts +57 -0
  198. package/src/models/ThemeConfig.ts +34 -0
  199. package/src/models/W3cExternalTraceAttributes.ts +22 -0
  200. package/src/modules/APM.ts +117 -0
  201. package/src/modules/BugReporting.ts +254 -0
  202. package/src/modules/CrashReporting.ts +54 -0
  203. package/src/modules/FeatureRequests.ts +32 -0
  204. package/src/modules/Luciq.ts +934 -0
  205. package/src/modules/NetworkLogger.ts +270 -0
  206. package/src/modules/Replies.ts +137 -0
  207. package/src/modules/SessionReplay.ts +111 -0
  208. package/src/modules/Surveys.ts +118 -0
  209. package/src/native/NativeAPM.ts +51 -0
  210. package/src/native/NativeBugReporting.ts +70 -0
  211. package/src/native/NativeConstants.ts +215 -0
  212. package/src/native/NativeCrashReporting.ts +29 -0
  213. package/src/native/NativeFeatureRequests.ts +12 -0
  214. package/src/native/NativeLuciq.ts +179 -0
  215. package/src/native/NativeNetworkLogger.ts +42 -0
  216. package/src/native/NativePackage.ts +25 -0
  217. package/src/native/NativeReplies.ts +34 -0
  218. package/src/native/NativeSessionReplay.ts +21 -0
  219. package/src/native/NativeSurveys.ts +34 -0
  220. package/src/promise.d.ts +11 -0
  221. package/src/utils/AppStatesHandler.ts +19 -0
  222. package/src/utils/Enums.ts +266 -0
  223. package/src/utils/FeatureFlags.ts +33 -0
  224. package/src/utils/LuciqConstants.ts +24 -0
  225. package/src/utils/LuciqUtils.ts +417 -0
  226. package/src/utils/UnhandledRejectionTracking.ts +118 -0
  227. package/src/utils/XhrNetworkInterceptor.ts +333 -0
  228. package/src/utils/config.ts +7 -0
  229. package/src/utils/logger.ts +54 -0
  230. package/tsconfig.json +32 -0
  231. package/tsconfig.test.json +4 -0
  232. package/tsconfig.upload.json +10 -0
  233. package/upload/index.d.ts +4 -0
  234. package/upload/index.js +17314 -0
  235. package/upload/migrate.d.ts +14 -0
  236. package/upload/package.json +5 -0
  237. package/upload/uploadEasUpdatesSourcemaps.d.ts +21 -0
  238. package/upload/uploadSoFiles.d.ts +21 -0
  239. package/upload/uploadSourcemaps.d.ts +21 -0
@@ -0,0 +1,5 @@
1
+ import { withLuciq } from './withLuciq';
2
+
3
+ export { withLuciq };
4
+
5
+ export default withLuciq;
@@ -0,0 +1,6 @@
1
+ export interface PluginProps {
2
+ name?: string;
3
+ forceUploadSourceMaps?: boolean;
4
+ addScreenRecordingBugReportingPermission?: boolean;
5
+ addBugReportingIosMediaPermission?: boolean;
6
+ }
@@ -0,0 +1,51 @@
1
+ import type { ConfigPlugin } from 'expo/config-plugins';
2
+ import { createRunOncePlugin } from 'expo/config-plugins';
3
+
4
+ import { withLuciqAndroid } from './withLuciqAndroid';
5
+ import { withLuciqIOS } from './withLuciqIOS';
6
+ import { PluginProps } from './pluginProps';
7
+
8
+ const luciqPackage = require('../../package.json') as {
9
+ name: string;
10
+ version: string;
11
+ };
12
+
13
+ const withLuciqPlugin: ConfigPlugin<PluginProps> = (config, props: PluginProps = {}) => {
14
+ const {
15
+ forceUploadSourceMaps = false,
16
+ addScreenRecordingBugReportingPermission = false,
17
+ addBugReportingIosMediaPermission = true,
18
+ } = props;
19
+
20
+ const sharedProps = {
21
+ ...props,
22
+ name: luciqPackage.name,
23
+ forceUploadSourceMaps,
24
+ addScreenRecordingBugReportingPermission,
25
+ addBugReportingIosMediaPermission,
26
+ };
27
+
28
+ let updatedConfig = config;
29
+
30
+ // Android configuration (only if source maps are enabled)
31
+ try {
32
+ updatedConfig = withLuciqAndroid(updatedConfig, sharedProps);
33
+ } catch (err) {
34
+ console.warn('[Luciq] Failed to configure Android project:', (err as Error).message ?? err);
35
+ }
36
+
37
+ // iOS configuration
38
+ try {
39
+ updatedConfig = withLuciqIOS(updatedConfig, sharedProps);
40
+ } catch (err) {
41
+ console.warn('[Luciq] Failed to configure iOS project:', (err as Error).message ?? err);
42
+ }
43
+
44
+ return updatedConfig;
45
+ };
46
+
47
+ export const withLuciq = createRunOncePlugin(
48
+ withLuciqPlugin,
49
+ luciqPackage.name,
50
+ luciqPackage.version,
51
+ );
@@ -0,0 +1,99 @@
1
+ import type { ConfigPlugin } from 'expo/config-plugins';
2
+ import { withAppBuildGradle, withAndroidManifest } from 'expo/config-plugins';
3
+ import type { PluginProps } from './pluginProps';
4
+
5
+ export const withLuciqAndroid: ConfigPlugin<PluginProps> = (config, props) => {
6
+ config = withAppBuildGradle(config, (configAndroid) => {
7
+ if (props.forceUploadSourceMaps) {
8
+ const gradle = configAndroid.modResults;
9
+ const packageName = props.name;
10
+
11
+ if (!packageName) {
12
+ console.warn('[Luciq] Missing "name" in plugin props. Skipping Android configuration.');
13
+ return configAndroid;
14
+ }
15
+
16
+ if (gradle.language === 'groovy') {
17
+ gradle.contents = injectGroovyScript(gradle.contents, packageName);
18
+ } else if (gradle.language === 'kt') {
19
+ gradle.contents = injectKotlinScript(gradle.contents, packageName);
20
+ } else {
21
+ throw new Error(
22
+ '[Luciq] Unsupported Gradle language. Only Groovy and Kotlin DSL are supported.',
23
+ );
24
+ }
25
+ }
26
+ return configAndroid;
27
+ });
28
+
29
+ // Inject the permission if requested
30
+ if (props.addScreenRecordingBugReportingPermission) {
31
+ config = withAndroidManifest(config, (configAndroid) => {
32
+ const manifest = configAndroid.modResults;
33
+
34
+ const permissionName = 'android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION';
35
+ const alreadyExists = manifest.manifest['uses-permission']?.some(
36
+ (permission: any) => permission.$?.['android:name'] === permissionName,
37
+ );
38
+
39
+ if (!alreadyExists) {
40
+ manifest.manifest['uses-permission'] = [
41
+ ...(manifest.manifest['uses-permission'] || []),
42
+ {
43
+ $: {
44
+ 'android:name': permissionName,
45
+ },
46
+ },
47
+ ];
48
+ }
49
+
50
+ return configAndroid;
51
+ });
52
+ }
53
+
54
+ return config;
55
+ };
56
+
57
+ // --- Helper Functions ---
58
+
59
+ function injectGroovyScript(buildGradle: string, packageName: string): string {
60
+ if (buildGradle.includes('sourcemaps.gradle')) {
61
+ return buildGradle;
62
+ }
63
+
64
+ const androidBlockPattern = /^android\s*{/m;
65
+ if (!androidBlockPattern.test(buildGradle)) {
66
+ console.warn('[Luciq] Could not find "android {" block in Groovy build.gradle.');
67
+ return buildGradle;
68
+ }
69
+
70
+ const script = `
71
+ def luciqPath = ["node", "--print", "require('path').dirname(require.resolve('${packageName}/package.json'))"]
72
+ .execute()
73
+ .text
74
+ .trim()
75
+ apply from: new File(luciqPath, "android/sourcemaps.gradle")
76
+ `.trim();
77
+
78
+ return buildGradle.replace(androidBlockPattern, `${script}\n\nandroid {`);
79
+ }
80
+
81
+ function injectKotlinScript(buildGradle: string, packageName: string): string {
82
+ if (buildGradle.includes('sourcemaps.gradle')) {
83
+ return buildGradle;
84
+ }
85
+
86
+ const androidBlockPattern = /^android\s*{/m;
87
+ if (!androidBlockPattern.test(buildGradle)) {
88
+ console.warn('[Luciq] Could not find "android {" block in Kotlin build.gradle.kts.');
89
+ return buildGradle;
90
+ }
91
+
92
+ const script = `
93
+ val luciqPath = listOf("node", "--print", "require('path').dirname(require.resolve("${packageName}/package.json"))")
94
+ .let { ProcessBuilder(it).start().inputStream.bufferedReader().readText().trim() }
95
+ apply(from = File(luciqPath, "android/sourcemaps.gradle"))
96
+ `.trim();
97
+
98
+ return buildGradle.replace(androidBlockPattern, `${script}\n\nandroid {`);
99
+ }
@@ -0,0 +1,109 @@
1
+ import type { ConfigPlugin, XcodeProject } from 'expo/config-plugins';
2
+ import { withXcodeProject, withInfoPlist } from 'expo/config-plugins';
3
+ import type { PluginProps } from './pluginProps';
4
+ import * as path from 'path';
5
+ import * as fs from 'fs';
6
+
7
+ const BUILD_PHASE = 'PBXShellScriptBuildPhase';
8
+ const PHASE_COMMENT = 'Bundle React Native code and images';
9
+ const LUCIQ_BUILD_PHASE = '[@luciq/react-native] Upload Sourcemap';
10
+
11
+ export const withLuciqIOS: ConfigPlugin<PluginProps> = (config, props) => {
12
+ let updatedConfig = withXcodeProject(config, (configXcode) => {
13
+ const xcodeProject = configXcode.modResults;
14
+ const buildPhases = xcodeProject.hash.project.objects[BUILD_PHASE];
15
+
16
+ if (!buildPhases) {
17
+ console.warn('[Luciq] No build phases found in Xcode project.');
18
+ return configXcode;
19
+ }
20
+
21
+ // Add Luciq build phase if not already present
22
+ const hasLuciqPhase = Boolean(findBuildPhase(buildPhases, LUCIQ_BUILD_PHASE));
23
+
24
+ if (!hasLuciqPhase && props.forceUploadSourceMaps) {
25
+ addLuciqBuildPhase(xcodeProject, props.name);
26
+ }
27
+
28
+ // Patch bundle React Native phase with source map export
29
+ const bundlePhase = xcodeProject.pbxItemByComment(PHASE_COMMENT, BUILD_PHASE);
30
+ if (bundlePhase?.shellScript) {
31
+ bundlePhase.shellScript = injectSourceMapExport(bundlePhase.shellScript);
32
+ }
33
+
34
+ return configXcode;
35
+ });
36
+
37
+ // Add media permissions to Info.plist if enabled
38
+ if (props.addBugReportingIosMediaPermission) {
39
+ const luciqConfig = config.extra?.luciq ?? {};
40
+
41
+ const microphonePermission =
42
+ luciqConfig.microphonePermission ||
43
+ 'This needs access to your microphone so you can attach voice notes.';
44
+
45
+ const photoLibraryPermission =
46
+ luciqConfig.photoLibraryPermission ||
47
+ 'This needs access to your photo library so you can attach images.';
48
+
49
+ updatedConfig = withInfoPlist(updatedConfig, (configXcode) => {
50
+ const plist = configXcode.ios.infoPlist ?? {};
51
+
52
+ if (!plist.NSMicrophoneUsageDescription) {
53
+ plist.NSMicrophoneUsageDescription = microphonePermission;
54
+ }
55
+
56
+ if (!plist.NSPhotoLibraryUsageDescription) {
57
+ plist.NSPhotoLibraryUsageDescription = photoLibraryPermission;
58
+ }
59
+
60
+ configXcode.ios.infoPlist = plist;
61
+ return configXcode;
62
+ });
63
+ }
64
+
65
+ return updatedConfig;
66
+ };
67
+
68
+ // Find a build phase by its clean name
69
+ function findBuildPhase(buildPhases: any, targetName: string): any | undefined {
70
+ const target = targetName.toLowerCase().trim();
71
+ return Object.values(buildPhases).find((phase: any) => {
72
+ const rawName = phase?.name ?? '';
73
+ const cleanName = rawName
74
+ .toLowerCase()
75
+ .replace('[cp-user] ', '')
76
+ .replace(/^"+|"+$/g, '')
77
+ .trim();
78
+ return cleanName === target;
79
+ });
80
+ }
81
+
82
+ // Inject Luciq shell script phase
83
+ function addLuciqBuildPhase(xcodeProject: XcodeProject, packageName: string): void {
84
+ try {
85
+ const packagePath = require.resolve(`${packageName}/package.json`);
86
+ const sourcemapScriptPath = path.join(path.dirname(packagePath), 'ios/sourcemaps.sh');
87
+
88
+ if (!fs.existsSync(sourcemapScriptPath)) {
89
+ console.warn(`[Luciq] sourcemaps.sh not found at: ${sourcemapScriptPath}`);
90
+ return;
91
+ }
92
+
93
+ xcodeProject.addBuildPhase([], BUILD_PHASE, LUCIQ_BUILD_PHASE, null, {
94
+ shellPath: '/bin/sh',
95
+ shellScript: `/bin/sh ${sourcemapScriptPath}`,
96
+ });
97
+ } catch (err) {
98
+ console.warn(`[Luciq] Failed to resolve package path for "${packageName}":`, err);
99
+ }
100
+ }
101
+
102
+ // Inject source map export line into the shell script
103
+ function injectSourceMapExport(script: string): string {
104
+ const exportLine = 'export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"';
105
+ const escapedLine = exportLine.replace(/\$/g, '\\$').replace(/"/g, '\\"');
106
+ const injectedLine = `${escapedLine}\\n`;
107
+
108
+ return script.includes(escapedLine) ? script : script.replace(/^"/, `"${injectedLine}`);
109
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "build",
4
+ "rootDir": "src"
5
+ },
6
+ "include": ["./src"]
7
+ }
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ ios: {
5
+ scriptPhases: [
6
+ {
7
+ name: '[@luciq/react-native] Upload Sourcemap',
8
+ path: './ios/sourcemaps.sh',
9
+ execution_position: 'after_compile',
10
+ },
11
+ ],
12
+ },
13
+ android: {},
14
+ },
15
+ },
16
+ };
@@ -0,0 +1,28 @@
1
+ #!/bin/bash
2
+
3
+ # Replaces the internal Config.plist file inside the Luciq iOS SDK with the
4
+ # Luciq.plist file in the example app.
5
+ #
6
+ # This is a workaround until the iOS SDK is updated to prioritize the custom
7
+ # Luciq.plist over the internal Config.plist.
8
+
9
+ luciq_plist=examples/default/ios/LuciqExample/LuciqConfig.plist
10
+
11
+ if [ ! -f $luciq_plist ]; then
12
+ echo "Luciq.plist not found"
13
+ exit 1
14
+ fi
15
+
16
+ for dir in examples/default/ios/Pods/Luciq/LuciqSDK.xcframework/ios-*/
17
+ do
18
+ echo "Replacing Config.plist in $dir"
19
+
20
+ config_path=$dir/LuciqSDK.framework/LuciqResources.bundle/Config.plist
21
+
22
+ if [ ! -f $config_path ]; then
23
+ echo "Config.plist not found in $dir"
24
+ exit 0
25
+ fi
26
+
27
+ cp -f $luciq_plist $config_path
28
+ done
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+
3
+ # remove survey and featureRequest features in JavaScript files
4
+ deletedFeaturesFilesInJavaScript=("Surveys" "FeatureRequests" "Survey")
5
+ for feature in "${deletedFeaturesFilesInJavaScript[@]}"; do
6
+ echo "$feature"
7
+
8
+ rm -f src/modules/"$feature".ts
9
+ rm -f src/native/Native"$feature".ts
10
+ rm -f test/mocks/mock"$feature".ts
11
+ rm -f test/modules/"$feature".spec.ts
12
+
13
+ node scripts/replace.js --pattern "import.+$feature';" "" src/index.ts
14
+ node scripts/replace.js --pattern "$feature," "" src/index.ts
15
+ node scripts/replace.js --pattern ".*$feature.*" "" src/native/NativePackage.ts
16
+ node scripts/replace.js --pattern ".*$feature.*" "" test/mocks/mockNativeModules.ts
17
+ done
18
+
19
+ npx eslint src/index.ts --fix
20
+
21
+ # remove survey and featureRequest features in Android files
22
+ deletedFeaturesFilesInAndroidApp=("RNLuciqSurveysModule" "RNLuciqFeatureRequestsModule")
23
+ for feature in "${deletedFeaturesFilesInAndroidApp[@]}"; do
24
+ echo "$feature"
25
+
26
+ rm -f android/src/main/java/ai/luciq/reactlibrary/"$feature".java
27
+ rm -f android/src/test/java/ai/luciq/reactlibrary/"$feature"Test.java
28
+ node scripts/replace.js "modules.add(new $feature(reactContext));" "" android/src/main/java/ai/luciq/reactlibrary/RNLuciqReactnativePackage.java
29
+ done
30
+
31
+ # remove survey and featureRequest features in IOS files
32
+ deletedFeaturesFilesInIosApp=("LuciqSurveysBridge" "LuciqFeatureRequestsBridge")
33
+ for feature in "${deletedFeaturesFilesInIosApp[@]}"; do
34
+ echo "$feature"
35
+ rm -f ios/RNLuciq/"$feature".h
36
+ rm -f ios/RNLuciq/"$feature".m
37
+ done
38
+
39
+ # Remove unused features iOS test files
40
+ iosTestFiles=("LuciqSurveysTests.m" "LuciqFeatureRequestsTests.m")
41
+ for file in "${iosTestFiles[@]}"; do
42
+ echo "Deleting $file"
43
+
44
+ rm -f examples/default/ios/LuciqTests/"$file"
45
+ node scripts/replace.js --pattern ".*$file.*" "" examples/default/ios/LuciqExample.xcodeproj/project.pbxproj
46
+ done
47
+
48
+ node scripts/replace.js "#import <Luciq/LQSurveys.h>" "" ios/RNLuciq/LuciqReactBridge.m
49
+ node scripts/replace.js "#import <Luciq/LQSurveys.h>" "" ios/RNLuciq/LuciqReactBridge.h
50
+
51
+ # Remove all locales except for English
52
+ # This ugly regular expression matches all lines not containing "english" and containing "constants.locale"
53
+ node scripts/replace.js --pattern "^(?!.*english).+constants\.locale.*" "" src/utils/Enums.ts
54
+ npx eslint src/index.ts --fix src/utils/Enums.ts
55
+
56
+ node scripts/replace.js "return (major == 7 && minor >= 3) || major >= 8" "return false" android/build.gradle
57
+
58
+ # Note: printf is used here as the string contains a newline character which would be escaped otherwise.
59
+ node scripts/replace.js "static boolean supportsNamespace() {" "$(printf "static boolean supportsNamespace() {\n return false")" android/build.gradle
60
+
61
+ # Add Dream11 custom iOS build podspec to Podfile
62
+ node scripts/replace.js "target 'LuciqExample' do" "$(printf "target 'LuciqExample' do\n pod 'Luciq', :podspec => 'https://ios-releases.luciq.ai/custom/dream11/Luciq.podspec'")" examples/default/ios/Podfile
@@ -0,0 +1,58 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const IGNORED_DIRS = new Set(['node_modules', 'ios', 'android']);
5
+ const INCLUDED_EXTENSIONS = new Set(['.js', '.ts', '.jsx', '.tsx']);
6
+
7
+ function getAllFiles(dir, fileList = []) {
8
+ const files = fs.readdirSync(dir);
9
+ for (const file of files) {
10
+ const fullPath = path.join(dir, file);
11
+ const stat = fs.statSync(fullPath);
12
+ if (stat.isDirectory()) {
13
+ if (!IGNORED_DIRS.has(file)) {
14
+ getAllFiles(fullPath, fileList);
15
+ }
16
+ } else {
17
+ if (INCLUDED_EXTENSIONS.has(path.extname(fullPath))) {
18
+ fileList.push(fullPath);
19
+ }
20
+ }
21
+ }
22
+ return fileList;
23
+ }
24
+
25
+ function extractTokenFromInit(content) {
26
+ const initMatch = content.match(/Luciq\.init\(\s*{[\s\S]*?token:\s*['"]([0-9a-zA-Z]+)['"]/);
27
+ return initMatch ? initMatch[1] : null;
28
+ }
29
+
30
+ function extractTokenFromStart(content) {
31
+ const startMatch = content.match(/Luciq\.start\(\s*['"]([0-9a-zA-Z]+)['"]/);
32
+ return startMatch ? startMatch[1] : null;
33
+ }
34
+
35
+ function findLuciqToken() {
36
+ const allFiles = getAllFiles('.');
37
+
38
+ for (const file of allFiles) {
39
+ const content = fs.readFileSync(file, 'utf-8');
40
+
41
+ const initToken = extractTokenFromInit(content);
42
+ if (initToken) {
43
+ console.log(initToken);
44
+ process.exit(0);
45
+ }
46
+
47
+ const startToken = extractTokenFromStart(content);
48
+ if (startToken) {
49
+ console.log(startToken);
50
+ process.exit(0);
51
+ }
52
+ }
53
+
54
+ console.log("Couldn't find Luciq's app token");
55
+ process.exit(1);
56
+ }
57
+
58
+ findLuciqToken();
@@ -0,0 +1,70 @@
1
+ #!/bin/sh
2
+
3
+ # Searches for app token within source files.
4
+ JSON_APP_TOKEN=$(
5
+ grep "app_token" -r -A 1 -m 1 --exclude-dir={node_modules,ios,android} --include=luciq.json ./ |
6
+ sed 's/[[:space:]]//g' |
7
+ grep -o ":[\"\'][0-9a-zA-Z]*[\"\']" |
8
+ cut -d ":" -f 2 |
9
+ cut -d "\"" -f 2 |
10
+ cut -d "'" -f 2
11
+ )
12
+
13
+ if [ ! -z "${JSON_APP_TOKEN}" ]; then
14
+ echo $JSON_APP_TOKEN
15
+ exit 0
16
+ fi
17
+
18
+ INIT_APP_TOKEN=$(
19
+ grep "Luciq.init({" -r -A 6 -m 1 --exclude-dir={node_modules,ios,android} --include=\*.{js,ts,jsx,tsx} ./ |
20
+ grep "token[[:space:]]*:[[:space:]]*[\"\'][0-9a-zA-Z]*[\"\']" |
21
+ grep -o "[\"\'][0-9a-zA-Z]*[\"\']" |
22
+ cut -d "\"" -f 2 |
23
+ cut -d "'" -f 2
24
+ )
25
+
26
+ if [ ! -z "${INIT_APP_TOKEN}" ]; then
27
+ echo $INIT_APP_TOKEN
28
+ exit 0
29
+ fi
30
+
31
+ START_APP_TOKEN=$(
32
+ grep "Luciq.start(" -r -A 1 -m 1 --exclude-dir={node_modules,ios,android} --include=\*.{js,ts,jsx,tsx} ./ |
33
+ grep -o "[\"\'][0-9a-zA-Z]*[\"\']" |
34
+ cut -d "\"" -f 2 |
35
+ cut -d "'" -f 2
36
+ )
37
+
38
+ if [ ! -z "${START_APP_TOKEN}" ]; then
39
+ echo $START_APP_TOKEN
40
+ exit 0
41
+ fi
42
+
43
+ ENV_APP_TOKEN=$(
44
+ grep "LUCIQ_APP_TOKEN" -r -A 1 -m 1 --exclude-dir={node_modules,ios,android} --include=\*.env ./ |
45
+ sed 's/[[:space:]]//g' |
46
+ grep -o "LUCIQ_APP_TOKEN=.*" |
47
+ cut -d "=" -f 2
48
+ )
49
+
50
+ if [ ! -z "${ENV_APP_TOKEN}" ]; then
51
+ echo $ENV_APP_TOKEN
52
+ exit 0
53
+ fi
54
+
55
+ CONSTANTS_APP_TOKEN=$(
56
+ grep "LUCIQ_APP_TOKEN" -r -A 1 -m 1 --exclude-dir={node_modules,ios,android} --include=\*.{js,ts,jsx,tsx} ./ |
57
+ sed 's/[[:space:]]//g' |
58
+ grep -o "=[\"\'][0-9a-zA-Z]*[\"\']" |
59
+ cut -d "=" -f 2 |
60
+ cut -d "\"" -f 2 |
61
+ cut -d "'" -f 2
62
+ )
63
+
64
+ if [ ! -z "${CONSTANTS_APP_TOKEN}" ]; then
65
+ echo $CONSTANTS_APP_TOKEN
66
+ exit 0
67
+ fi
68
+
69
+ echo "Couldn't find Luciq's app token"
70
+ exit 1
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+
3
+ pr_url="https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls?head=$CIRCLE_PROJECT_USERNAME:$CIRCLE_BRANCH&state=open"
4
+ pr_response=$(curl --location --request GET "$pr_url" --header "Authorization: Bearer $RELEASE_GITHUB_TOKEN")
5
+
6
+ if [ $(echo "$pr_response" | jq length) -eq 0 ]; then
7
+ echo "No PR found to update"
8
+ else
9
+ pr_comment_url=$(echo "$pr_response" | jq -r ".[]._links.comments.href")
10
+
11
+ curl --location --request POST "$pr_comment_url" \
12
+ --header 'Content-Type: application/json' \
13
+ --header "Authorization: Bearer $RELEASE_GITHUB_TOKEN" \
14
+ --data-raw "$1"
15
+ fi
@@ -0,0 +1,58 @@
1
+ /**
2
+ * A script to replace all occurrences of a string in a file, this is built as a
3
+ * replacement for the `sed` command to make it easier to replace strings with
4
+ * special characters without the hassle of escaping them, this is important
5
+ * when we are replacing strings that aren't known in advance like parameters
6
+ * from files.
7
+ *
8
+ * Usage: node replace.js <search> <replace> <file>
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { parseArgs } = require('util');
14
+
15
+ const { values, positionals } = parseArgs({
16
+ allowPositionals: true,
17
+ options: {
18
+ pattern: {
19
+ type: 'boolean',
20
+ default: false,
21
+ short: 'p',
22
+ },
23
+ },
24
+ });
25
+
26
+ const [search, replace, ...files] = positionals;
27
+
28
+ /** Whether to replace the search string as a regular expression or as a literal string. */
29
+ const isPattern = values.pattern;
30
+
31
+ if (search == null || replace == null || !files.length) {
32
+ // The path of the script relative to the directory where the user ran the
33
+ // script to be used in the error message demonstrating the usage.
34
+ const scriptPath = path.relative(process.cwd(), __filename);
35
+
36
+ console.error('Missing arguments.');
37
+ console.table({ search, replace, files });
38
+
39
+ console.error(`Usage: node ${scriptPath} [-p | --pattern] <search> <replace> <files...>`);
40
+ process.exit(1);
41
+ }
42
+
43
+ for (const file of files) {
44
+ try {
45
+ const filePath = path.resolve(process.cwd(), file);
46
+
47
+ const fileContent = fs.readFileSync(filePath, 'utf8');
48
+
49
+ const searchPattern = isPattern ? new RegExp(search, 'gm') : search;
50
+ const newContent = fileContent.replaceAll(searchPattern, replace);
51
+
52
+ fs.writeFileSync(filePath, newContent);
53
+ } catch (error) {
54
+ console.error(`An error occurred while replacing the content of the file: ${file}.`);
55
+ console.error(error);
56
+ process.exit(1);
57
+ }
58
+ }
@@ -0,0 +1,15 @@
1
+ Your snapshot has been generated! :rocket:
2
+
3
+ ### Installation
4
+
5
+ You can install the snapshot through NPM:
6
+
7
+ ```sh
8
+ npm install @luciq/react-native@{VERSION}
9
+ ```
10
+
11
+ or Yarn:
12
+
13
+ ```sh
14
+ yarn add @luciq/react-native@{VERSION}
15
+ ```
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ # Generates a snapshot version following the format {version}-{pr}{random-3-digit}-SNAPSHOT
4
+ # Example: 13.3.0-502861-SNAPSHOT
5
+
6
+ pr=$(basename $CIRCLE_PULL_REQUEST)
7
+ random=$(($RANDOM % 900 + 100))
8
+ version=$(jq -r '.version' package.json)
9
+ suffix="SNAPSHOT"
10
+
11
+ SNAPSHOT_VERSION="$version-$pr$random-$suffix"
package/src/index.ts ADDED
@@ -0,0 +1,40 @@
1
+ // Models
2
+ import type { LuciqConfig } from './models/LuciqConfig';
3
+ import Report from './models/Report';
4
+ import type { ThemeConfig } from './models/ThemeConfig';
5
+ // Modules
6
+ import * as APM from './modules/APM';
7
+ import * as BugReporting from './modules/BugReporting';
8
+ import * as CrashReporting from './modules/CrashReporting';
9
+ import * as FeatureRequests from './modules/FeatureRequests';
10
+ import * as Luciq from './modules/Luciq';
11
+ import * as NetworkLogger from './modules/NetworkLogger';
12
+ import type { NetworkData, NetworkDataObfuscationHandler } from './modules/NetworkLogger';
13
+ import * as Replies from './modules/Replies';
14
+ import type { Survey } from './modules/Surveys';
15
+ import * as Surveys from './modules/Surveys';
16
+ import * as SessionReplay from './modules/SessionReplay';
17
+ import type { SessionMetadata } from './models/SessionMetadata';
18
+
19
+ export * from './utils/Enums';
20
+ export {
21
+ Report,
22
+ APM,
23
+ BugReporting,
24
+ CrashReporting,
25
+ FeatureRequests,
26
+ NetworkLogger,
27
+ SessionReplay,
28
+ Replies,
29
+ Surveys,
30
+ };
31
+ export type {
32
+ LuciqConfig,
33
+ Survey,
34
+ NetworkData,
35
+ NetworkDataObfuscationHandler,
36
+ SessionMetadata,
37
+ ThemeConfig,
38
+ };
39
+
40
+ export default Luciq;
@@ -0,0 +1,12 @@
1
+ export interface FeatureFlag {
2
+ /**
3
+ * the name of feature flag
4
+ */
5
+ name: string;
6
+
7
+ /**
8
+ * The variant of the feature flag.
9
+ * Leave it `undefined` for boolean (kill switch) feature flags.
10
+ */
11
+ variant?: string;
12
+ }