@datadog/mobile-react-native-session-replay 2.12.3 → 2.13.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 (60) hide show
  1. package/DatadogSDKReactNativeSessionReplay.podspec +6 -2
  2. package/README.md +90 -1
  3. package/android/build.gradle +3 -2
  4. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +2 -2
  5. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeInternalCallback.kt +121 -0
  6. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt +5 -1
  7. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt +1 -0
  8. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/SvgViewMapper.kt +145 -0
  9. package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyView.kt +10 -0
  10. package/android/src/newarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +13 -0
  11. package/android/src/oldarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +13 -0
  12. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementationTest.kt +8 -0
  13. package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt +21 -5
  14. package/assets/assets.bin +0 -0
  15. package/assets/assets.json +1 -0
  16. package/ios/Sources/DdPrivacyViewFabric.h +28 -0
  17. package/ios/Sources/DdPrivacyViewFabric.mm +22 -4
  18. package/ios/Sources/DdPrivacyViewPaper.m +24 -0
  19. package/ios/Sources/DdSessionReplayImplementation.swift +34 -6
  20. package/ios/Sources/SvgViewRecorder.swift +233 -0
  21. package/ios/Sources/Utils/Bundle+SessionReplay.swift +21 -0
  22. package/lib/commonjs/components/SessionReplayView/PrivacyView.js +2 -0
  23. package/lib/commonjs/components/SessionReplayView/PrivacyView.js.map +1 -1
  24. package/lib/commonjs/metro/index.js +75 -0
  25. package/lib/commonjs/metro/index.js.map +1 -0
  26. package/lib/commonjs/metro/processing.js +97 -0
  27. package/lib/commonjs/metro/processing.js.map +1 -0
  28. package/lib/commonjs/metro/utils.js +20 -0
  29. package/lib/commonjs/metro/utils.js.map +1 -0
  30. package/lib/commonjs/specs/DdPrivacyViewNativeComponent.js.map +1 -1
  31. package/lib/module/components/SessionReplayView/PrivacyView.js +2 -0
  32. package/lib/module/components/SessionReplayView/PrivacyView.js.map +1 -1
  33. package/lib/module/metro/index.js +68 -0
  34. package/lib/module/metro/index.js.map +1 -0
  35. package/lib/module/metro/processing.js +90 -0
  36. package/lib/module/metro/processing.js.map +1 -0
  37. package/lib/module/metro/utils.js +14 -0
  38. package/lib/module/metro/utils.js.map +1 -0
  39. package/lib/module/specs/DdPrivacyViewNativeComponent.js.map +1 -1
  40. package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts +10 -1
  41. package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts.map +1 -1
  42. package/lib/typescript/metro/index.d.ts +2 -0
  43. package/lib/typescript/metro/index.d.ts.map +1 -0
  44. package/lib/typescript/metro/processing.d.ts +9 -0
  45. package/lib/typescript/metro/processing.d.ts.map +1 -0
  46. package/lib/typescript/metro/utils.d.ts +2 -0
  47. package/lib/typescript/metro/utils.d.ts.map +1 -0
  48. package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts +8 -0
  49. package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts.map +1 -1
  50. package/lib/typescript/types/DdPrivacyView.d.ts +8 -0
  51. package/lib/typescript/types/DdPrivacyView.d.ts.map +1 -1
  52. package/metro.js +7 -0
  53. package/package.json +9 -3
  54. package/scripts/build-assets.js +31 -0
  55. package/src/components/SessionReplayView/PrivacyView.tsx +11 -0
  56. package/src/metro/index.ts +82 -0
  57. package/src/metro/processing.ts +119 -0
  58. package/src/metro/utils.ts +17 -0
  59. package/src/specs/DdPrivacyViewNativeComponent.ts +9 -0
  60. package/src/types/DdPrivacyView.ts +9 -0
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.debounce = debounce;
7
+ /*
8
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
9
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
10
+ * Copyright 2016-Present Datadog, Inc.
11
+ */
12
+
13
+ function debounce(fn, ms) {
14
+ let timer;
15
+ return (...args) => {
16
+ clearTimeout(timer);
17
+ timer = setTimeout(() => fn(...args), ms);
18
+ };
19
+ }
20
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["debounce","fn","ms","timer","args","clearTimeout","setTimeout"],"sourceRoot":"../../../src","sources":["metro/utils.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;;AAEO,SAASA,QAAQA,CACpBC,EAAK,EACLC,EAAU,EACT;EACD,IAAIC,KAAqB;EAEzB,OAAQ,CAAC,GAAGC,IAAmB,KAAK;IAChCC,YAAY,CAACF,KAAK,CAAC;IACnBA,KAAK,GAAGG,UAAU,CAAC,MAAML,EAAE,CAAC,GAAGG,IAAI,CAAC,EAAEF,EAAE,CAAC;EAC7C,CAAC;AACL","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["_codegenNativeComponent","_interopRequireDefault","require","e","__esModule","default","_default","exports","codegenNativeComponent","paperComponentName"],"sourceRoot":"../../../src","sources":["specs/DdPrivacyViewNativeComponent.ts"],"mappings":";;;;;;AAMA,IAAAA,uBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA6F,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAN7F;AACA;AACA;AACA;AACA;AAJA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAgBe,IAAAG,+BAAsB,EAAqB,eAAe,EAAE;EACvEC,kBAAkB,EAAE;AACxB,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["_codegenNativeComponent","_interopRequireDefault","require","e","__esModule","default","_default","exports","codegenNativeComponent","paperComponentName"],"sourceRoot":"../../../src","sources":["specs/DdPrivacyViewNativeComponent.ts"],"mappings":";;;;;;AAMA,IAAAA,uBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA6F,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAN7F;AACA;AACA;AACA;AACA;AAJA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAyBe,IAAAG,+BAAsB,EAAqB,eAAe,EAAE;EACvEC,kBAAkB,EAAE;AACxB,CAAC,CAAC","ignoreList":[]}
@@ -24,6 +24,7 @@ export function PrivacyView({
24
24
  textAndInputPrivacy,
25
25
  imagePrivacy,
26
26
  touchPrivacy,
27
+ nativeID,
27
28
  hide = false,
28
29
  ...props
29
30
  }) {
@@ -33,6 +34,7 @@ export function PrivacyView({
33
34
  imagePrivacy: imagePrivacy,
34
35
  touchPrivacy: touchPrivacy,
35
36
  hide: hide || false,
37
+ nativeID: nativeID,
36
38
  children: children
37
39
  });
38
40
  }
@@ -1 +1 @@
1
- {"version":3,"names":["React","View","jsx","_jsx","PrivacyView","children","textAndInputPrivacy","imagePrivacy","touchPrivacy","hide","props"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/PrivacyView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAGA,OAAOA,KAAK,MAAM,OAAO;AAOzB,OAAOC,IAAI,MAAM,2BAA2B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAqB7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CAAC;EACxBC,QAAQ;EACRC,mBAAmB;EACnBC,YAAY;EACZC,YAAY;EACZC,IAAI,GAAG,KAAK;EACZ,GAAGC;AACA,CAAC,EAAE;EACN,oBACIP,IAAA,CAACF,IAAI;IAAA,GACGS,KAAK;IACTJ,mBAAmB,EAAEA,mBAA8B;IACnDC,YAAY,EAAEA,YAAuB;IACrCC,YAAY,EAAEA,YAAuB;IACrCC,IAAI,EAAEA,IAAI,IAAI,KAAM;IAAAJ,QAAA,EAEnBA;EAAQ,CACP,CAAC;AAEf","ignoreList":[]}
1
+ {"version":3,"names":["React","View","jsx","_jsx","PrivacyView","children","textAndInputPrivacy","imagePrivacy","touchPrivacy","nativeID","hide","props"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/PrivacyView.tsx"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAGA,OAAOA,KAAK,MAAM,OAAO;AAOzB,OAAOC,IAAI,MAAM,2BAA2B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AA8B7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CAAC;EACxBC,QAAQ;EACRC,mBAAmB;EACnBC,YAAY;EACZC,YAAY;EACZC,QAAQ;EACRC,IAAI,GAAG,KAAK;EACZ,GAAGC;AACA,CAAC,EAAE;EACN,oBACIR,IAAA,CAACF,IAAI;IAAA,GACGU,KAAK;IACTL,mBAAmB,EAAEA,mBAA8B;IACnDC,YAAY,EAAEA,YAAuB;IACrCC,YAAY,EAAEA,YAAuB;IACrCE,IAAI,EAAEA,IAAI,IAAI,KAAM;IACpBD,QAAQ,EAAEA,QAAmB;IAAAJ,QAAA,EAE5BA;EAAQ,CACP,CAAC;AAEf","ignoreList":[]}
@@ -0,0 +1,68 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ import chokidar from 'chokidar';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { mergeSvgAssets } from './processing';
11
+ import { debounce } from './utils';
12
+ let watching = false;
13
+ const MERGE_DEBOUNCE_MS = 300;
14
+ const WATCH_STABILITY_THRESHOLD_MS = 200;
15
+ const WATCH_POLL_INTERVAL_MS = 50;
16
+ export function withSessionReplayAssetBundler(metroConfig) {
17
+ const originalReporter = metroConfig.reporter;
18
+ const assetsDir = path.resolve(__dirname, '../../../assets');
19
+ if (!fs.existsSync(assetsDir)) {
20
+ fs.mkdirSync(assetsDir, {
21
+ recursive: true
22
+ });
23
+ }
24
+ const debounceMerge = debounce(() => {
25
+ try {
26
+ mergeSvgAssets(assetsDir);
27
+ } catch (error) {
28
+ console.warn('[SessionReplayAssetBundler] SVGs merge failed:', error);
29
+ }
30
+ }, MERGE_DEBOUNCE_MS);
31
+
32
+ // Prevent potential multiple watchers if metro loads the config multiple times
33
+ if (!watching) {
34
+ watching = true;
35
+ chokidar.watch(assetsDir, {
36
+ // Skip events for files that already exist
37
+ ignoreInitial: true,
38
+ depth: 0,
39
+ awaitWriteFinish: {
40
+ // Wait 200ms after last change
41
+ stabilityThreshold: WATCH_STABILITY_THRESHOLD_MS,
42
+ // Check every 50ms
43
+ pollInterval: WATCH_POLL_INTERVAL_MS
44
+ }
45
+ }).on('add', file => {
46
+ if (!file.endsWith('.svg')) {
47
+ return;
48
+ }
49
+ debounceMerge();
50
+ });
51
+ }
52
+ return {
53
+ ...metroConfig,
54
+ reporter: {
55
+ update(event) {
56
+ if (originalReporter?.update) {
57
+ originalReporter.update(event);
58
+ }
59
+
60
+ // https://github.com/facebook/metro/blob/main/packages/metro/src/lib/reporting.js
61
+ if (event.type === 'bundle_build_done' || event.type === 'transformer_load_done') {
62
+ mergeSvgAssets(assetsDir);
63
+ }
64
+ }
65
+ }
66
+ };
67
+ }
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["chokidar","fs","path","mergeSvgAssets","debounce","watching","MERGE_DEBOUNCE_MS","WATCH_STABILITY_THRESHOLD_MS","WATCH_POLL_INTERVAL_MS","withSessionReplayAssetBundler","metroConfig","originalReporter","reporter","assetsDir","resolve","__dirname","existsSync","mkdirSync","recursive","debounceMerge","error","console","warn","watch","ignoreInitial","depth","awaitWriteFinish","stabilityThreshold","pollInterval","on","file","endsWith","update","event","type"],"sourceRoot":"../../../src","sources":["metro/index.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,QAAQ,MAAM,UAAU;AAC/B,OAAOC,EAAE,MAAM,IAAI;AACnB,OAAOC,IAAI,MAAM,MAAM;AAEvB,SAASC,cAAc,QAAQ,cAAc;AAC7C,SAASC,QAAQ,QAAQ,SAAS;AAElC,IAAIC,QAAQ,GAAG,KAAK;AAEpB,MAAMC,iBAAiB,GAAG,GAAG;AAC7B,MAAMC,4BAA4B,GAAG,GAAG;AACxC,MAAMC,sBAAsB,GAAG,EAAE;AAEjC,OAAO,SAASC,6BAA6BA,CAACC,WAAgB,EAAO;EACjE,MAAMC,gBAAgB,GAAGD,WAAW,CAACE,QAAQ;EAE7C,MAAMC,SAAS,GAAGX,IAAI,CAACY,OAAO,CAACC,SAAS,EAAE,iBAAiB,CAAC;EAE5D,IAAI,CAACd,EAAE,CAACe,UAAU,CAACH,SAAS,CAAC,EAAE;IAC3BZ,EAAE,CAACgB,SAAS,CAACJ,SAAS,EAAE;MAAEK,SAAS,EAAE;IAAK,CAAC,CAAC;EAChD;EAEA,MAAMC,aAAa,GAAGf,QAAQ,CAAC,MAAM;IACjC,IAAI;MACAD,cAAc,CAACU,SAAS,CAAC;IAC7B,CAAC,CAAC,OAAOO,KAAK,EAAE;MACZC,OAAO,CAACC,IAAI,CACR,gDAAgD,EAChDF,KACJ,CAAC;IACL;EACJ,CAAC,EAAEd,iBAAiB,CAAC;;EAErB;EACA,IAAI,CAACD,QAAQ,EAAE;IACXA,QAAQ,GAAG,IAAI;IACfL,QAAQ,CACHuB,KAAK,CAACV,SAAS,EAAE;MACd;MACAW,aAAa,EAAE,IAAI;MACnBC,KAAK,EAAE,CAAC;MACRC,gBAAgB,EAAE;QACd;QACAC,kBAAkB,EAAEpB,4BAA4B;QAChD;QACAqB,YAAY,EAAEpB;MAClB;IACJ,CAAC,CAAC,CACDqB,EAAE,CAAC,KAAK,EAAEC,IAAI,IAAI;MACf,IAAI,CAACA,IAAI,CAACC,QAAQ,CAAC,MAAM,CAAC,EAAE;QACxB;MACJ;MAEAZ,aAAa,CAAC,CAAC;IACnB,CAAC,CAAC;EACV;EAEA,OAAO;IACH,GAAGT,WAAW;IACdE,QAAQ,EAAE;MACNoB,MAAMA,CAACC,KAAU,EAAE;QACf,IAAItB,gBAAgB,EAAEqB,MAAM,EAAE;UAC1BrB,gBAAgB,CAACqB,MAAM,CAACC,KAAK,CAAC;QAClC;;QAEA;QACA,IACIA,KAAK,CAACC,IAAI,KAAK,mBAAmB,IAClCD,KAAK,CAACC,IAAI,KAAK,uBAAuB,EACxC;UACE/B,cAAc,CAACU,SAAS,CAAC;QAC7B;MACJ;IACJ;EACJ,CAAC;AACL","ignoreList":[]}
@@ -0,0 +1,90 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ /**
10
+ * Removes the binary and JSON asset files from the specified directory.
11
+ * This is used to clean up corrupted or partial asset files before regenerating them.
12
+ *
13
+ * @param binPath - Absolute path to the assets.bin file
14
+ * @param jsonPath - Absolute path to the assets.json file
15
+ */
16
+ function cleanupFiles(binPath, jsonPath) {
17
+ try {
18
+ fs.unlinkSync(binPath);
19
+ } catch (err) {
20
+ console.warn('[cleanupFiles] Failed to cleanup binary assets', err);
21
+ }
22
+ try {
23
+ fs.unlinkSync(jsonPath);
24
+ } catch (err) {
25
+ console.warn('[cleanupFiles] Failed to cleanup json assets', err);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Merges all individual SVG files into assets.bin and creates an index in assets.json.
31
+ * This function reads all .svg files from the assets directory and packs them into
32
+ * a single binary file with an accompanying JSON index for efficient lookup.
33
+ *
34
+ * @param assetsDir - Absolute path to the assets directory
35
+ */
36
+ export function mergeSvgAssets(assetsDir) {
37
+ try {
38
+ const binName = 'assets.bin';
39
+ const jsonName = 'assets.json';
40
+ const binPath = path.resolve(assetsDir, binName);
41
+ const jsonPath = path.resolve(assetsDir, jsonName);
42
+ let index = {};
43
+ let offset = 0;
44
+ if (!fs.existsSync(assetsDir)) {
45
+ fs.mkdirSync(assetsDir, {
46
+ recursive: true
47
+ });
48
+ }
49
+ try {
50
+ const jsonData = fs.readFileSync(jsonPath, 'utf8');
51
+ const binStats = fs.statSync(binPath);
52
+ index = JSON.parse(jsonData);
53
+ offset = binStats.size;
54
+ } catch (err) {
55
+ console.warn('[mergeSvgAssets] Assets missing or corrupted, starting fresh');
56
+ index = {};
57
+ offset = 0;
58
+ cleanupFiles(binPath, jsonPath);
59
+ }
60
+ const files = fs.readdirSync(assetsDir).filter(f => f.endsWith('.svg')).sort();
61
+ let added = 0;
62
+ for (const f of files) {
63
+ const id = path.basename(f, path.extname(f));
64
+ if (index[id]) {
65
+ continue;
66
+ }
67
+ try {
68
+ const svg = fs.readFileSync(path.join(assetsDir, f), 'utf8');
69
+ const buf = Buffer.from(svg, 'utf8');
70
+ const length = buf.length;
71
+ fs.appendFileSync(binPath, buf);
72
+ index[id] = {
73
+ offset,
74
+ length
75
+ };
76
+ offset += length;
77
+ added++;
78
+ } catch (err) {
79
+ console.warn(`[SessionReplayAssetBundler] Failed to process ${f}:`, err);
80
+ }
81
+ }
82
+ fs.writeFileSync(jsonPath, JSON.stringify(index, null, 2));
83
+ if (added > 0) {
84
+ console.info(`[SessionReplayAssetBundler] Packed ${added} new Session Replay SVG assets → total: ${Object.keys(index).length}`);
85
+ }
86
+ } catch (err) {
87
+ console.error('[mergeSvgAssets] Unexpected error during asset merge', err);
88
+ }
89
+ }
90
+ //# sourceMappingURL=processing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["fs","path","cleanupFiles","binPath","jsonPath","unlinkSync","err","console","warn","mergeSvgAssets","assetsDir","binName","jsonName","resolve","index","offset","existsSync","mkdirSync","recursive","jsonData","readFileSync","binStats","statSync","JSON","parse","size","files","readdirSync","filter","f","endsWith","sort","added","id","basename","extname","svg","join","buf","Buffer","from","length","appendFileSync","writeFileSync","stringify","info","Object","keys","error"],"sourceRoot":"../../../src","sources":["metro/processing.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ export function debounce(fn, ms) {
8
+ let timer;
9
+ return (...args) => {
10
+ clearTimeout(timer);
11
+ timer = setTimeout(() => fn(...args), ms);
12
+ };
13
+ }
14
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["debounce","fn","ms","timer","args","clearTimeout","setTimeout"],"sourceRoot":"../../../src","sources":["metro/utils.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,OAAO,SAASA,QAAQA,CACpBC,EAAK,EACLC,EAAU,EACT;EACD,IAAIC,KAAqB;EAEzB,OAAQ,CAAC,GAAGC,IAAmB,KAAK;IAChCC,YAAY,CAACF,KAAK,CAAC;IACnBA,KAAK,GAAGG,UAAU,CAAC,MAAML,EAAE,CAAC,GAAGG,IAAI,CAAC,EAAEF,EAAE,CAAC;EAC7C,CAAC;AACL","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["codegenNativeComponent","paperComponentName"],"sourceRoot":"../../../src","sources":["specs/DdPrivacyViewNativeComponent.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,sBAAsB,MAAM,yDAAyD;AAU5F,eAAeA,sBAAsB,CAAqB,eAAe,EAAE;EACvEC,kBAAkB,EAAE;AACxB,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["codegenNativeComponent","paperComponentName"],"sourceRoot":"../../../src","sources":["specs/DdPrivacyViewNativeComponent.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA,OAAOA,sBAAsB,MAAM,yDAAyD;AAmB5F,eAAeA,sBAAsB,CAAqB,eAAe,EAAE;EACvEC,kBAAkB,EAAE;AACxB,CAAC,CAAC","ignoreList":[]}
@@ -1,6 +1,7 @@
1
1
  import type { ViewProps } from 'react-native';
2
2
  import React from 'react';
3
3
  import type { ImagePrivacyLevel, TextAndInputPrivacyLevel, TouchPrivacyLevel } from '../../SessionReplay';
4
+ import type { Attributes } from '../../types/DdPrivacyView';
4
5
  type Props = ViewProps & {
5
6
  /**
6
7
  * Controls how text and input fields are masked in session replays.
@@ -18,6 +19,14 @@ type Props = ViewProps & {
18
19
  * When true, completely hides this view and its children from session replays.
19
20
  */
20
21
  hide?: boolean;
22
+ /**
23
+ * When set, allows the view to be uniquely identifiable in the native layer.
24
+ */
25
+ nativeID?: string;
26
+ /**
27
+ * When set, allows view attributes to be passed to the native layer.
28
+ */
29
+ attributes?: Attributes;
21
30
  };
22
31
  /**
23
32
  * A low-level component for configuring session replay privacy behavior with more granular control over the properties.
@@ -31,6 +40,6 @@ type Props = ViewProps & {
31
40
  * - Whether touch interactions are visible
32
41
  * - Whether the entire view should be hidden from replays
33
42
  */
34
- export declare function PrivacyView({ children, textAndInputPrivacy, imagePrivacy, touchPrivacy, hide, ...props }: Props): React.JSX.Element;
43
+ export declare function PrivacyView({ children, textAndInputPrivacy, imagePrivacy, touchPrivacy, nativeID, hide, ...props }: Props): React.JSX.Element;
35
44
  export {};
36
45
  //# sourceMappingURL=PrivacyView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PrivacyView.d.ts","sourceRoot":"","sources":["../../../../src/components/SessionReplayView/PrivacyView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EACR,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACpB,MAAM,qBAAqB,CAAC;AAG7B,KAAK,KAAK,GAAG,SAAS,GAAG;IACrB;;OAEG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EACxB,QAAQ,EACR,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,IAAY,EACZ,GAAG,KAAK,EACX,EAAE,KAAK,qBAYP"}
1
+ {"version":3,"file":"PrivacyView.d.ts","sourceRoot":"","sources":["../../../../src/components/SessionReplayView/PrivacyView.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EACR,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,KAAK,KAAK,GAAG,SAAS,GAAG;IACrB;;OAEG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;OAEG;IACH,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,EACxB,QAAQ,EACR,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,IAAY,EACZ,GAAG,KAAK,EACX,EAAE,KAAK,qBAaP"}
@@ -0,0 +1,2 @@
1
+ export declare function withSessionReplayAssetBundler(metroConfig: any): any;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/metro/index.ts"],"names":[],"mappings":"AAmBA,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,GAAG,GAAG,GAAG,CA8DnE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Merges all individual SVG files into assets.bin and creates an index in assets.json.
3
+ * This function reads all .svg files from the assets directory and packs them into
4
+ * a single binary file with an accompanying JSON index for efficient lookup.
5
+ *
6
+ * @param assetsDir - Absolute path to the assets directory
7
+ */
8
+ export declare function mergeSvgAssets(assetsDir: string): void;
9
+ //# sourceMappingURL=processing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processing.d.ts","sourceRoot":"","sources":["../../../src/metro/processing.ts"],"names":[],"mappings":"AAqCA;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,QA0E/C"}
@@ -0,0 +1,2 @@
1
+ export declare function debounce<T extends (...args: any[]) => void>(fn: T, ms: number): T;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/metro/utils.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,EACvD,EAAE,EAAE,CAAC,EACL,EAAE,EAAE,MAAM,GACX,CAAC,CAOH"}
@@ -1,9 +1,17 @@
1
1
  import type { HostComponent, ViewProps } from 'react-native';
2
+ type Attributes = {
3
+ type?: string;
4
+ hash?: string;
5
+ width?: string;
6
+ height?: string;
7
+ };
2
8
  interface DdPrivacyViewProps extends ViewProps {
3
9
  textAndInputPrivacy: string;
4
10
  imagePrivacy: string;
5
11
  touchPrivacy: string;
6
12
  hide: boolean;
13
+ nativeID: string;
14
+ attributes: Attributes;
7
15
  }
8
16
  declare const _default: HostComponent<DdPrivacyViewProps>;
9
17
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"DdPrivacyViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/specs/DdPrivacyViewNativeComponent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7D,UAAU,kBAAmB,SAAQ,SAAS;IAC1C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;CACjB;;AAED,wBAEwC"}
1
+ {"version":3,"file":"DdPrivacyViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/specs/DdPrivacyViewNativeComponent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7D,KAAK,UAAU,GAAG;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,UAAU,kBAAmB,SAAQ,SAAS;IAC1C,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CAC1B;;AAED,wBAEwC"}
@@ -1,8 +1,16 @@
1
1
  import type { ViewProps } from 'react-native';
2
+ export type Attributes = {
3
+ type?: string;
4
+ hash?: string;
5
+ width?: string;
6
+ height?: string;
7
+ };
2
8
  export interface DdPrivacyViewProps extends ViewProps {
3
9
  textAndInputPrivacy: string;
4
10
  imagePrivacy: string;
5
11
  touchPrivacy: string;
6
12
  hide: boolean;
13
+ nativeID: string;
14
+ attributes: Attributes;
7
15
  }
8
16
  //# sourceMappingURL=DdPrivacyView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DdPrivacyView.d.ts","sourceRoot":"","sources":["../../../src/types/DdPrivacyView.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACjD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;CACjB"}
1
+ {"version":3,"file":"DdPrivacyView.d.ts","sourceRoot":"","sources":["../../../src/types/DdPrivacyView.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACjD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CAC1B"}
package/metro.js ADDED
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ module.exports = require('./lib/commonjs/metro/index.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datadog/mobile-react-native-session-replay",
3
- "version": "2.12.3",
3
+ "version": "2.13.0",
4
4
  "description": "A client-side React Native module to enable session replay with Datadog",
5
5
  "keywords": [
6
6
  "datadog",
@@ -19,7 +19,9 @@
19
19
  "files": [
20
20
  "src/**",
21
21
  "lib/**",
22
+ "assets/**",
22
23
  "scripts/**",
24
+ "metro.js",
23
25
  "android/build.gradle",
24
26
  "android/detekt.yml",
25
27
  "android/gradle.properties",
@@ -41,7 +43,8 @@
41
43
  "scripts": {
42
44
  "test": "jest",
43
45
  "lint": "eslint .",
44
- "prepare": "rm -rf lib && yarn bob build",
46
+ "build:assets": "node scripts/build-assets.js",
47
+ "prepare": "rm -rf lib && yarn build:assets && yarn bob build",
45
48
  "postinstall": "node scripts/set-ios-rn-version.js"
46
49
  },
47
50
  "peerDependencies": {
@@ -90,5 +93,8 @@
90
93
  "javaPackageName": "com.datadog.reactnative.sessionreplay"
91
94
  }
92
95
  },
93
- "gitHead": "842123f32b952c593ae1339b50a328f94c391929"
96
+ "dependencies": {
97
+ "chokidar": "^4.0.3"
98
+ },
99
+ "gitHead": "3031bc89a36c50e85227d0ab3755b236213f4dbf"
94
100
  }
@@ -0,0 +1,31 @@
1
+ /* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
2
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
3
+ * Copyright 2016-Present Datadog, Inc.
4
+ */
5
+
6
+ /* eslint-disable @typescript-eslint/no-var-requires */
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const assetsDir = path.resolve(__dirname, '..', 'assets');
11
+ const binPath = path.join(assetsDir, 'assets.bin');
12
+ const jsonPath = path.join(assetsDir, 'assets.json');
13
+
14
+ function ensureAssets() {
15
+ try {
16
+ if (fs.existsSync(assetsDir)) {
17
+ fs.rmSync(assetsDir, { recursive: true, force: true });
18
+ }
19
+
20
+ fs.mkdirSync(assetsDir, { recursive: true });
21
+
22
+ fs.writeFileSync(binPath, Buffer.alloc(0));
23
+
24
+ fs.writeFileSync(jsonPath, JSON.stringify({}, null, 2));
25
+ } catch (error) {
26
+ console.error('Error creating assets:', error.message);
27
+ process.exit(1);
28
+ }
29
+ }
30
+
31
+ ensureAssets();
@@ -13,6 +13,7 @@ import type {
13
13
  TouchPrivacyLevel
14
14
  } from '../../SessionReplay';
15
15
  import View from '../../specs/DdPrivacyView';
16
+ import type { Attributes } from '../../types/DdPrivacyView';
16
17
 
17
18
  type Props = ViewProps & {
18
19
  /**
@@ -31,6 +32,14 @@ type Props = ViewProps & {
31
32
  * When true, completely hides this view and its children from session replays.
32
33
  */
33
34
  hide?: boolean;
35
+ /**
36
+ * When set, allows the view to be uniquely identifiable in the native layer.
37
+ */
38
+ nativeID?: string;
39
+ /**
40
+ * When set, allows view attributes to be passed to the native layer.
41
+ */
42
+ attributes?: Attributes;
34
43
  };
35
44
 
36
45
  /**
@@ -50,6 +59,7 @@ export function PrivacyView({
50
59
  textAndInputPrivacy,
51
60
  imagePrivacy,
52
61
  touchPrivacy,
62
+ nativeID,
53
63
  hide = false,
54
64
  ...props
55
65
  }: Props) {
@@ -60,6 +70,7 @@ export function PrivacyView({
60
70
  imagePrivacy={imagePrivacy as string}
61
71
  touchPrivacy={touchPrivacy as string}
62
72
  hide={hide || false}
73
+ nativeID={nativeID as string}
63
74
  >
64
75
  {children}
65
76
  </View>
@@ -0,0 +1,82 @@
1
+ /*
2
+ * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
3
+ * This product includes software developed at Datadog (https://www.datadoghq.com/).
4
+ * Copyright 2016-Present Datadog, Inc.
5
+ */
6
+
7
+ import chokidar from 'chokidar';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ import { mergeSvgAssets } from './processing';
12
+ import { debounce } from './utils';
13
+
14
+ let watching = false;
15
+
16
+ const MERGE_DEBOUNCE_MS = 300;
17
+ const WATCH_STABILITY_THRESHOLD_MS = 200;
18
+ const WATCH_POLL_INTERVAL_MS = 50;
19
+
20
+ export function withSessionReplayAssetBundler(metroConfig: any): any {
21
+ const originalReporter = metroConfig.reporter;
22
+
23
+ const assetsDir = path.resolve(__dirname, '../../../assets');
24
+
25
+ if (!fs.existsSync(assetsDir)) {
26
+ fs.mkdirSync(assetsDir, { recursive: true });
27
+ }
28
+
29
+ const debounceMerge = debounce(() => {
30
+ try {
31
+ mergeSvgAssets(assetsDir);
32
+ } catch (error) {
33
+ console.warn(
34
+ '[SessionReplayAssetBundler] SVGs merge failed:',
35
+ error
36
+ );
37
+ }
38
+ }, MERGE_DEBOUNCE_MS);
39
+
40
+ // Prevent potential multiple watchers if metro loads the config multiple times
41
+ if (!watching) {
42
+ watching = true;
43
+ chokidar
44
+ .watch(assetsDir, {
45
+ // Skip events for files that already exist
46
+ ignoreInitial: true,
47
+ depth: 0,
48
+ awaitWriteFinish: {
49
+ // Wait 200ms after last change
50
+ stabilityThreshold: WATCH_STABILITY_THRESHOLD_MS,
51
+ // Check every 50ms
52
+ pollInterval: WATCH_POLL_INTERVAL_MS
53
+ }
54
+ })
55
+ .on('add', file => {
56
+ if (!file.endsWith('.svg')) {
57
+ return;
58
+ }
59
+
60
+ debounceMerge();
61
+ });
62
+ }
63
+
64
+ return {
65
+ ...metroConfig,
66
+ reporter: {
67
+ update(event: any) {
68
+ if (originalReporter?.update) {
69
+ originalReporter.update(event);
70
+ }
71
+
72
+ // https://github.com/facebook/metro/blob/main/packages/metro/src/lib/reporting.js
73
+ if (
74
+ event.type === 'bundle_build_done' ||
75
+ event.type === 'transformer_load_done'
76
+ ) {
77
+ mergeSvgAssets(assetsDir);
78
+ }
79
+ }
80
+ }
81
+ };
82
+ }