@cloudcare/cocos-sdk 0.1.0-alpha.1

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 (161) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +31 -0
  3. package/THIRD_PARTY_NOTICES +5 -0
  4. package/bin/cli.cjs +127 -0
  5. package/creator2/package.json +4 -0
  6. package/creator3/package.json +5 -0
  7. package/dist/creator2/core/auto-tracking.d.ts +35 -0
  8. package/dist/creator2/core/auto-tracking.d.ts.map +1 -0
  9. package/dist/creator2/core/auto-tracking.js +337 -0
  10. package/dist/creator2/core/auto-tracking.js.map +1 -0
  11. package/dist/creator2/core/client.d.ts +74 -0
  12. package/dist/creator2/core/client.d.ts.map +1 -0
  13. package/dist/creator2/core/client.js +176 -0
  14. package/dist/creator2/core/client.js.map +1 -0
  15. package/dist/creator2/core/index.d.ts +3 -0
  16. package/dist/creator2/core/index.d.ts.map +1 -0
  17. package/dist/creator2/core/index.js +6 -0
  18. package/dist/creator2/core/index.js.map +1 -0
  19. package/dist/creator2/core/modules.d.ts +159 -0
  20. package/dist/creator2/core/modules.d.ts.map +1 -0
  21. package/dist/creator2/core/modules.js +319 -0
  22. package/dist/creator2/core/modules.js.map +1 -0
  23. package/dist/creator2/core/replay-budget.d.ts +28 -0
  24. package/dist/creator2/core/replay-budget.d.ts.map +1 -0
  25. package/dist/creator2/core/replay-budget.js +113 -0
  26. package/dist/creator2/core/replay-budget.js.map +1 -0
  27. package/dist/creator2/core/replay-diagnostics.d.ts +36 -0
  28. package/dist/creator2/core/replay-diagnostics.d.ts.map +1 -0
  29. package/dist/creator2/core/replay-diagnostics.js +40 -0
  30. package/dist/creator2/core/replay-diagnostics.js.map +1 -0
  31. package/dist/creator2/core/replay-encoding.d.ts +31 -0
  32. package/dist/creator2/core/replay-encoding.d.ts.map +1 -0
  33. package/dist/creator2/core/replay-encoding.js +63 -0
  34. package/dist/creator2/core/replay-encoding.js.map +1 -0
  35. package/dist/creator2/core/replay-pixels.d.ts +3 -0
  36. package/dist/creator2/core/replay-pixels.d.ts.map +1 -0
  37. package/dist/creator2/core/replay-pixels.js +16 -0
  38. package/dist/creator2/core/replay-pixels.js.map +1 -0
  39. package/dist/creator2/core/replay.d.ts +97 -0
  40. package/dist/creator2/core/replay.d.ts.map +1 -0
  41. package/dist/creator2/core/replay.js +578 -0
  42. package/dist/creator2/core/replay.js.map +1 -0
  43. package/dist/creator2/core/transport.d.ts +16 -0
  44. package/dist/creator2/core/transport.d.ts.map +1 -0
  45. package/dist/creator2/core/transport.js +33 -0
  46. package/dist/creator2/core/transport.js.map +1 -0
  47. package/dist/creator2/core/types.d.ts +260 -0
  48. package/dist/creator2/core/types.d.ts.map +1 -0
  49. package/dist/creator2/core/types.js +3 -0
  50. package/dist/creator2/core/types.js.map +1 -0
  51. package/dist/creator2/core/validation.d.ts +14 -0
  52. package/dist/creator2/core/validation.d.ts.map +1 -0
  53. package/dist/creator2/core/validation.js +81 -0
  54. package/dist/creator2/core/validation.js.map +1 -0
  55. package/dist/creator2/core/version.d.ts +9 -0
  56. package/dist/creator2/core/version.d.ts.map +1 -0
  57. package/dist/creator2/core/version.js +14 -0
  58. package/dist/creator2/core/version.js.map +1 -0
  59. package/dist/creator2/creator2/auto.d.ts +9 -0
  60. package/dist/creator2/creator2/auto.d.ts.map +1 -0
  61. package/dist/creator2/creator2/auto.js +65 -0
  62. package/dist/creator2/creator2/auto.js.map +1 -0
  63. package/dist/creator2/creator2/capture.d.ts +17 -0
  64. package/dist/creator2/creator2/capture.d.ts.map +1 -0
  65. package/dist/creator2/creator2/capture.js +162 -0
  66. package/dist/creator2/creator2/capture.js.map +1 -0
  67. package/dist/creator2/creator2/index.d.ts +12 -0
  68. package/dist/creator2/creator2/index.d.ts.map +1 -0
  69. package/dist/creator2/creator2/index.js +41 -0
  70. package/dist/creator2/creator2/index.js.map +1 -0
  71. package/dist/creator2/creator2/transport.d.ts +7 -0
  72. package/dist/creator2/creator2/transport.d.ts.map +1 -0
  73. package/dist/creator2/creator2/transport.js +34 -0
  74. package/dist/creator2/creator2/transport.js.map +1 -0
  75. package/dist/creator3/core/auto-tracking.d.ts +35 -0
  76. package/dist/creator3/core/auto-tracking.d.ts.map +1 -0
  77. package/dist/creator3/core/auto-tracking.js +247 -0
  78. package/dist/creator3/core/auto-tracking.js.map +1 -0
  79. package/dist/creator3/core/client.d.ts +74 -0
  80. package/dist/creator3/core/client.d.ts.map +1 -0
  81. package/dist/creator3/core/client.js +158 -0
  82. package/dist/creator3/core/client.js.map +1 -0
  83. package/dist/creator3/core/index.d.ts +3 -0
  84. package/dist/creator3/core/index.d.ts.map +1 -0
  85. package/dist/creator3/core/index.js +2 -0
  86. package/dist/creator3/core/index.js.map +1 -0
  87. package/dist/creator3/core/modules.d.ts +159 -0
  88. package/dist/creator3/core/modules.d.ts.map +1 -0
  89. package/dist/creator3/core/modules.js +293 -0
  90. package/dist/creator3/core/modules.js.map +1 -0
  91. package/dist/creator3/core/replay-budget.d.ts +28 -0
  92. package/dist/creator3/core/replay-budget.d.ts.map +1 -0
  93. package/dist/creator3/core/replay-budget.js +105 -0
  94. package/dist/creator3/core/replay-budget.js.map +1 -0
  95. package/dist/creator3/core/replay-diagnostics.d.ts +36 -0
  96. package/dist/creator3/core/replay-diagnostics.d.ts.map +1 -0
  97. package/dist/creator3/core/replay-diagnostics.js +36 -0
  98. package/dist/creator3/core/replay-diagnostics.js.map +1 -0
  99. package/dist/creator3/core/replay-encoding.d.ts +31 -0
  100. package/dist/creator3/core/replay-encoding.d.ts.map +1 -0
  101. package/dist/creator3/core/replay-encoding.js +62 -0
  102. package/dist/creator3/core/replay-encoding.js.map +1 -0
  103. package/dist/creator3/core/replay-pixels.d.ts +3 -0
  104. package/dist/creator3/core/replay-pixels.d.ts.map +1 -0
  105. package/dist/creator3/core/replay-pixels.js +13 -0
  106. package/dist/creator3/core/replay-pixels.js.map +1 -0
  107. package/dist/creator3/core/replay.d.ts +97 -0
  108. package/dist/creator3/core/replay.d.ts.map +1 -0
  109. package/dist/creator3/core/replay.js +520 -0
  110. package/dist/creator3/core/replay.js.map +1 -0
  111. package/dist/creator3/core/transport.d.ts +16 -0
  112. package/dist/creator3/core/transport.d.ts.map +1 -0
  113. package/dist/creator3/core/transport.js +27 -0
  114. package/dist/creator3/core/transport.js.map +1 -0
  115. package/dist/creator3/core/types.d.ts +260 -0
  116. package/dist/creator3/core/types.d.ts.map +1 -0
  117. package/dist/creator3/core/types.js +2 -0
  118. package/dist/creator3/core/types.js.map +1 -0
  119. package/dist/creator3/core/validation.d.ts +14 -0
  120. package/dist/creator3/core/validation.d.ts.map +1 -0
  121. package/dist/creator3/core/validation.js +75 -0
  122. package/dist/creator3/core/validation.js.map +1 -0
  123. package/dist/creator3/core/version.d.ts +9 -0
  124. package/dist/creator3/core/version.d.ts.map +1 -0
  125. package/dist/creator3/core/version.js +11 -0
  126. package/dist/creator3/core/version.js.map +1 -0
  127. package/dist/creator3/creator3/auto.d.ts +9 -0
  128. package/dist/creator3/creator3/auto.d.ts.map +1 -0
  129. package/dist/creator3/creator3/auto.js +45 -0
  130. package/dist/creator3/creator3/auto.js.map +1 -0
  131. package/dist/creator3/creator3/capture.d.ts +17 -0
  132. package/dist/creator3/creator3/capture.d.ts.map +1 -0
  133. package/dist/creator3/creator3/capture.js +117 -0
  134. package/dist/creator3/creator3/capture.js.map +1 -0
  135. package/dist/creator3/creator3/index.d.ts +12 -0
  136. package/dist/creator3/creator3/index.d.ts.map +1 -0
  137. package/dist/creator3/creator3/index.js +23 -0
  138. package/dist/creator3/creator3/index.js.map +1 -0
  139. package/dist/creator3/creator3/replay-render-cycle.d.ts +9 -0
  140. package/dist/creator3/creator3/replay-render-cycle.d.ts.map +1 -0
  141. package/dist/creator3/creator3/replay-render-cycle.js +12 -0
  142. package/dist/creator3/creator3/replay-render-cycle.js.map +1 -0
  143. package/dist/creator3/creator3/transport.d.ts +8 -0
  144. package/dist/creator3/creator3/transport.d.ts.map +1 -0
  145. package/dist/creator3/creator3/transport.js +24 -0
  146. package/dist/creator3/creator3/transport.js.map +1 -0
  147. package/dist/creator3/package.json +1 -0
  148. package/extensions/creator2/install-native.cjs +333 -0
  149. package/extensions/creator2/main.js +23 -0
  150. package/extensions/creator2/package.json +6 -0
  151. package/extensions/creator3/dist/builder.js +9 -0
  152. package/extensions/creator3/dist/hooks.js +70 -0
  153. package/extensions/creator3/dist/main.js +4 -0
  154. package/extensions/creator3/install-native.cjs +333 -0
  155. package/extensions/creator3/package.json +10 -0
  156. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridge.java +532 -0
  157. package/native/android/src/main/java/com/ft/sdk/cocos/FTCocosBridgeProvider.java +70 -0
  158. package/native/ios/FTCocosBridge.h +10 -0
  159. package/native/ios/FTCocosBridge.m +470 -0
  160. package/native/ios/FTCocosBridge.podspec +18 -0
  161. package/package.json +60 -0
@@ -0,0 +1,117 @@
1
+ import { Camera, Director, EditBox, RenderTexture, UITransform, director, native, sys, view } from 'cc';
2
+ import { frameFingerprint } from '../core/replay.js';
3
+ import { waitForRenderTextureReadback } from './replay-render-cycle.js';
4
+ export class FTCreator3CanvasCapture {
5
+ constructor() {
6
+ this.privacy = new Map();
7
+ }
8
+ setCamera(camera) {
9
+ this.camera = camera;
10
+ }
11
+ setPrivacy(node, mode) {
12
+ if (mode === 'unmask')
13
+ this.privacy.delete(node);
14
+ else
15
+ this.privacy.set(node, mode);
16
+ }
17
+ getViewportSize() {
18
+ var _a;
19
+ const visible = ((_a = view.getVisibleSizeInPixel) === null || _a === void 0 ? void 0 : _a.call(view)) || view.getVisibleSize();
20
+ return visible ? { width: visible.width, height: visible.height } : undefined;
21
+ }
22
+ async capture(maxImageDimension) {
23
+ var _a, _b;
24
+ const camera = this.camera || ((_a = director.getScene()) === null || _a === void 0 ? void 0 : _a.getComponentInChildren(Camera));
25
+ if (!camera)
26
+ return undefined;
27
+ const visible = this.getViewportSize();
28
+ if (!visible)
29
+ return undefined;
30
+ const scale = Math.min(1, maxImageDimension / Math.max(visible.width, visible.height));
31
+ const width = Math.max(1, Math.round(visible.width * scale));
32
+ const height = Math.max(1, Math.round(visible.height * scale));
33
+ const texture = new RenderTexture();
34
+ texture.reset({ width, height });
35
+ const previous = camera.targetTexture;
36
+ let pixels;
37
+ try {
38
+ camera.targetTexture = texture;
39
+ await waitForRenderTextureReadback(completeDrawCycle);
40
+ pixels = texture.readPixels(0, 0, width, height);
41
+ }
42
+ finally {
43
+ camera.targetTexture = previous;
44
+ texture.destroy();
45
+ }
46
+ if (!pixels)
47
+ return undefined;
48
+ // Metal returns top-down pixels on iOS. OpenGL/Vulkan-backed native
49
+ // targets use a bottom-left origin and need row reversal for PNG output.
50
+ if (sys.os !== ((_b = sys.OS) === null || _b === void 0 ? void 0 : _b.IOS))
51
+ flipRows(pixels, width, height);
52
+ return {
53
+ rgba: pixels,
54
+ width,
55
+ height,
56
+ timestamp: Date.now(),
57
+ privacyRegions: this.collectPrivacyRegions(width, height, visible.width, visible.height),
58
+ };
59
+ }
60
+ async persist(frame, fingerprint = frameFingerprint(frame.rgba)) {
61
+ const path = `${native.fileUtils.getWritablePath()}cocos-sdk-replay-${fingerprint}.rgba`;
62
+ if (!native.fileUtils.writeDataToFile(frame.rgba, path)) {
63
+ throw new Error(`Unable to persist replay frame: ${path}`);
64
+ }
65
+ return { path, width: frame.width, height: frame.height, timestamp: frame.timestamp, fingerprint };
66
+ }
67
+ disposeStoredFrame(frame) {
68
+ if (native.fileUtils.isFileExist(frame.path))
69
+ native.fileUtils.removeFile(frame.path);
70
+ }
71
+ collectPrivacyRegions(width, height, sourceWidth, sourceHeight) {
72
+ var _a, _b;
73
+ const nodes = new Map(this.privacy);
74
+ (_b = (_a = director.getScene()) === null || _a === void 0 ? void 0 : _a.getComponentsInChildren(EditBox)) === null || _b === void 0 ? void 0 : _b.forEach((editBox) => {
75
+ if (!nodes.has(editBox.node))
76
+ nodes.set(editBox.node, 'mask');
77
+ });
78
+ const scaleX = width / sourceWidth;
79
+ const scaleY = height / sourceHeight;
80
+ const regions = [];
81
+ nodes.forEach((mode, node) => {
82
+ var _a, _b, _c;
83
+ const bounds = (_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.getComponent) === null || _a === void 0 ? void 0 : _a.call(node, UITransform)) === null || _b === void 0 ? void 0 : _b.getBoundingBoxToWorld) === null || _c === void 0 ? void 0 : _c.call(_b);
84
+ if (!bounds)
85
+ return;
86
+ regions.push({
87
+ x: bounds.x * scaleX,
88
+ y: height - (bounds.y + bounds.height) * scaleY,
89
+ width: bounds.width * scaleX,
90
+ height: bounds.height * scaleY,
91
+ mode: mode === 'hide' ? 'hide' : 'mask',
92
+ });
93
+ });
94
+ return regions;
95
+ }
96
+ }
97
+ async function completeDrawCycle() {
98
+ // capture() may run after the current frame's render graph has already been
99
+ // prepared. Waiting only for EVENT_AFTER_DRAW can then read the newly bound
100
+ // RenderTexture before the camera has rendered into it, producing a black
101
+ // FullSnapshot at a Native -> Cocos boundary. Start at the next draw boundary
102
+ // so the target texture is guaranteed to participate in a complete frame.
103
+ await new Promise((resolve) => director.once(Director.EVENT_BEFORE_DRAW, resolve));
104
+ await new Promise((resolve) => director.once(Director.EVENT_AFTER_DRAW, resolve));
105
+ }
106
+ function flipRows(bytes, width, height) {
107
+ const rowSize = width * 4;
108
+ const swap = new Uint8Array(rowSize);
109
+ for (let top = 0, bottom = height - 1; top < bottom; top += 1, bottom -= 1) {
110
+ const topOffset = top * rowSize;
111
+ const bottomOffset = bottom * rowSize;
112
+ swap.set(bytes.subarray(topOffset, topOffset + rowSize));
113
+ bytes.copyWithin(topOffset, bottomOffset, bottomOffset + rowSize);
114
+ bytes.set(swap, bottomOffset);
115
+ }
116
+ }
117
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../../../../src/creator3/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAGxG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAExE,MAAM,OAAO,uBAAuB;IAApC;QAEU,YAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IAuF5D,CAAC;IArFC,SAAS,CAAC,MAAe;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,UAAU,CAAC,IAAa,EAAE,IAAyB;QACjD,IAAI,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;;YAC5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,eAAe;;QACb,MAAM,OAAO,GAAG,CAAA,MAAA,IAAI,CAAC,qBAAqB,oDAAI,KAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxE,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,iBAAyB;;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAI,MAAA,QAAQ,CAAC,QAAQ,EAAE,0CAAE,sBAAsB,CAAC,MAAM,CAAC,CAAA,CAAC;QAClF,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QACvF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;QACpC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC;QACtC,IAAI,MAA8B,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,CAAC,aAAa,GAAG,OAAO,CAAC;YAC/B,MAAM,4BAA4B,CAAC,iBAAiB,CAAC,CAAC;YACtD,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACnD,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,aAAa,GAAG,QAAQ,CAAC;YAChC,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAC9B,oEAAoE;QACpE,yEAAyE;QACzE,IAAI,GAAG,CAAC,EAAE,MAAK,MAAA,GAAG,CAAC,EAAE,0CAAE,GAAG,CAAA;YAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5D,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,KAAK;YACL,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,cAAc,EAAE,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;SACzF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAsB,EAAE,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC;QAC9E,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE,oBAAoB,WAAW,OAAO,CAAC;QACzF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC;IACrG,CAAC;IAED,kBAAkB,CAAC,KAAoB;QACrC,IAAI,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxF,CAAC;IAEO,qBAAqB,CAC3B,KAAa,EACb,MAAc,EACd,WAAmB,EACnB,YAAoB;;QAEpB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpC,MAAA,MAAA,QAAQ,CAAC,QAAQ,EAAE,0CAAE,uBAAuB,CAAC,OAAO,CAAC,0CAAE,OAAO,CAAC,CAAC,OAAY,EAAE,EAAE;YAC9E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;QACrC,MAAM,OAAO,GAAsB,EAAE,CAAC;QACtC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,IAAS,EAAE,EAAE;;YAChC,MAAM,MAAM,GAAG,MAAA,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,qDAAG,WAAW,CAAC,0CAAE,qBAAqB,kDAAI,CAAC;YAC5E,IAAI,CAAC,MAAM;gBAAE,OAAO;YACpB,OAAO,CAAC,IAAI,CAAC;gBACX,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM;gBACpB,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM;gBAC/C,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,MAAM;gBAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM;gBAC9B,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;aACxC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED,KAAK,UAAU,iBAAiB;IAC9B,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC;IACzF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,QAAQ,CAAC,KAAiB,EAAE,KAAa,EAAE,MAAc;IAChE,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;IACrC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;QAC3E,MAAM,SAAS,GAAG,GAAG,GAAG,OAAO,CAAC;QAChC,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;QACzD,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC;QAClE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAChC,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { FTCocosSDK } from '../core/client.js';
2
+ /** Shared SDK entry point for Cocos Creator 3.x applications. */
3
+ export declare const guanceSdk: FTCocosSDK;
4
+ /**
5
+ * Selects the Cocos Creator 3 camera used to capture Session Replay frames.
6
+ * Call this after the camera is available and before starting Replay.
7
+ *
8
+ * @param camera - Active Cocos `Camera` component.
9
+ */
10
+ export declare function setReplayCamera(camera: unknown): void;
11
+ export * from '../core/index.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAgB/C,iEAAiE;AACjE,eAAO,MAAM,SAAS,YAA0D,CAAC;AAEjF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAErD;AAED,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { FTDefaultAutoTracking } from '../core/auto-tracking.js';
2
+ import { FTCocosSDK } from '../core/client.js';
3
+ import { FTLogger, FTRUM, FTTrace } from '../core/modules.js';
4
+ import { FTCreator3TrackingHooks } from './auto.js';
5
+ import { FTCreator3CanvasCapture } from './capture.js';
6
+ import { FTCreator3Transport } from './transport.js';
7
+ const transport = new FTCreator3Transport();
8
+ const capture = new FTCreator3CanvasCapture();
9
+ const hooks = new FTCreator3TrackingHooks();
10
+ const autoTracking = new FTDefaultAutoTracking(new FTRUM(transport), new FTLogger(transport), new FTTrace(transport), hooks);
11
+ /** Shared SDK entry point for Cocos Creator 3.x applications. */
12
+ export const guanceSdk = new FTCocosSDK(transport, capture, autoTracking, hooks);
13
+ /**
14
+ * Selects the Cocos Creator 3 camera used to capture Session Replay frames.
15
+ * Call this after the camera is available and before starting Replay.
16
+ *
17
+ * @param camera - Active Cocos `Camera` component.
18
+ */
19
+ export function setReplayCamera(camera) {
20
+ capture.setCamera(camera);
21
+ }
22
+ export * from '../core/index.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/creator3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,SAAS,GAAG,IAAI,mBAAmB,EAAE,CAAC;AAC5C,MAAM,OAAO,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAC9C,MAAM,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAC;AAC5C,MAAM,YAAY,GAAG,IAAI,qBAAqB,CAC5C,IAAI,KAAK,CAAC,SAAS,CAAC,EACpB,IAAI,QAAQ,CAAC,SAAS,CAAC,EACvB,IAAI,OAAO,CAAC,SAAS,CAAC,EACtB,KAAK,CACN,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAe;IAC7C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Waits until a newly attached native RenderTexture is safe to read back.
3
+ *
4
+ * Creator 3 can submit the first draw while the target attachment is still
5
+ * being applied by the native renderer. Keeping the target attached for a
6
+ * second complete draw prevents an empty first Session Replay snapshot.
7
+ */
8
+ export declare function waitForRenderTextureReadback(drawCycle: () => Promise<void>): Promise<void>;
9
+ //# sourceMappingURL=replay-render-cycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-render-cycle.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/replay-render-cycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAsB,4BAA4B,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Waits until a newly attached native RenderTexture is safe to read back.
3
+ *
4
+ * Creator 3 can submit the first draw while the target attachment is still
5
+ * being applied by the native renderer. Keeping the target attached for a
6
+ * second complete draw prevents an empty first Session Replay snapshot.
7
+ */
8
+ export async function waitForRenderTextureReadback(drawCycle) {
9
+ await drawCycle();
10
+ await drawCycle();
11
+ }
12
+ //# sourceMappingURL=replay-render-cycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay-render-cycle.js","sourceRoot":"","sources":["../../../../../src/creator3/replay-render-cycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,SAA8B;IAC/E,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type FTNativeTransport } from '../core/transport.js';
2
+ import type { FTValue } from '../core/types.js';
3
+ export declare class FTCreator3Transport implements FTNativeTransport {
4
+ readonly platform: 'android' | 'ios' | 'unsupported';
5
+ constructor();
6
+ invoke<T = FTValue>(method: string, payload?: unknown): T | undefined;
7
+ }
8
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../../../src/creator3/transport.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,KAAK,GAAG,aAAa,CAAC;;IAYrD,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,GAAG,SAAS;CActE"}
@@ -0,0 +1,24 @@
1
+ import { native, sys } from 'cc';
2
+ import { NATIVE } from 'cc/env';
3
+ import { parseTransportResponse } from '../core/transport.js';
4
+ export class FTCreator3Transport {
5
+ constructor() {
6
+ this.platform = !NATIVE
7
+ ? 'unsupported'
8
+ : sys.os === sys.OS.ANDROID
9
+ ? 'android'
10
+ : sys.os === sys.OS.IOS
11
+ ? 'ios'
12
+ : 'unsupported';
13
+ }
14
+ invoke(method, payload) {
15
+ if (this.platform === 'unsupported')
16
+ return undefined;
17
+ const json = payload === undefined ? '{}' : JSON.stringify(payload);
18
+ const raw = this.platform === 'android'
19
+ ? native.reflection.callStaticMethod('com/ft/sdk/cocos/FTCocosBridge', 'invoke', '(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;', method, json)
20
+ : native.reflection.callStaticMethod('FTCocosBridge', 'invoke:payload:', method, json);
21
+ return parseTransportResponse(raw);
22
+ }
23
+ }
24
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../../src/creator3/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,sBAAsB,EAA0B,MAAM,sBAAsB,CAAC;AAGtF,MAAM,OAAO,mBAAmB;IAG9B;QACE,IAAI,CAAC,QAAQ,GAAG,CAAC,MAAM;YACrB,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,OAAO;gBACzB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG;oBACrB,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,aAAa,CAAC;IACxB,CAAC;IAED,MAAM,CAAc,MAAc,EAAE,OAAiB;QACnD,IAAI,IAAI,CAAC,QAAQ,KAAK,aAAa;YAAE,OAAO,SAAS,CAAC;QACtD,MAAM,IAAI,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS;YACrC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAChC,gCAAgC,EAChC,QAAQ,EACR,0DAA0D,EAC1D,MAAM,EACN,IAAI,CACL;YACH,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,eAAe,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACzF,OAAO,sBAAsB,CAAI,GAAG,CAAC,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,333 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execFileSync } = require('child_process');
6
+
7
+ const BEGIN = '/* COCOS_SDK_BEGIN */';
8
+ const END = '/* COCOS_SDK_END */';
9
+ const POD_BEGIN = '# COCOS_SDK_BEGIN';
10
+ const POD_END = '# COCOS_SDK_END';
11
+ const XCCONFIG_BEGIN = '// COCOS_SDK_BEGIN';
12
+ const XCCONFIG_END = '// COCOS_SDK_END';
13
+ const LEGACY_BEGIN = '/* FT_COCOS_SDK_BEGIN */';
14
+ const LEGACY_END = '/* FT_COCOS_SDK_END */';
15
+ const LEGACY_POD_BEGIN = '# FT_COCOS_SDK_BEGIN';
16
+ const LEGACY_POD_END = '# FT_COCOS_SDK_END';
17
+ const LEGACY_XCCONFIG_BEGIN = '// FT_COCOS_SDK_BEGIN';
18
+ const LEGACY_XCCONFIG_END = '// FT_COCOS_SDK_END';
19
+
20
+ function installNative(buildRoot, extensionRoot, logger = console) {
21
+ if (!buildRoot) return;
22
+ buildRoot = path.resolve(buildRoot);
23
+ extensionRoot = path.resolve(extensionRoot);
24
+ if (!fs.existsSync(buildRoot)) return;
25
+ const nativeSource = path.join(extensionRoot, 'native');
26
+ if (!fs.existsSync(nativeSource)) {
27
+ logger.warn(`[cocos-sdk] Native bridge not found at ${nativeSource}`);
28
+ return;
29
+ }
30
+ const buildNative = path.join(buildRoot, 'cocos-sdk-native');
31
+ copyDirectory(nativeSource, buildNative);
32
+ const files = findFiles(buildRoot, 7);
33
+ const gradlePropertiesFiles = files.filter((file) => path.basename(file) === 'gradle.properties');
34
+ const gradleFiles = uniqueFiles([
35
+ ...files.filter((file) => /(?:^|\/)app\/build\.gradle$/.test(normalize(file))),
36
+ ...gradlePropertiesFiles.flatMap(findNativeAppGradleFiles),
37
+ ]);
38
+ const podfiles = files.filter((file) => path.basename(file) === 'Podfile');
39
+ const xcodeProjects = files.filter((file) => (
40
+ path.basename(file) === 'project.pbxproj' && path.extname(path.dirname(file)) === '.xcodeproj'
41
+ ));
42
+ const iosApplicationProjects = xcodeProjects
43
+ .map((projectFile) => ({ projectFile, target: findIosApplicationTarget(projectFile) }))
44
+ .filter((project) => project.target);
45
+ if (podfiles.length === 0) {
46
+ iosApplicationProjects.forEach(({ projectFile, target }) => {
47
+ const projectDirectory = path.dirname(path.dirname(projectFile));
48
+ const podfile = path.join(projectDirectory, 'Podfile');
49
+ if (!fs.existsSync(podfile)) createPodfile(podfile, projectFile, target);
50
+ podfiles.push(podfile);
51
+ });
52
+ }
53
+ iosApplicationProjects.forEach(({ projectFile, target }) => {
54
+ patchCocos2IosConfiguration(projectFile, target);
55
+ });
56
+ gradleFiles.forEach((file) => patchGradle(file, buildNative));
57
+ gradlePropertiesFiles.forEach(patchGradleProperties);
58
+ podfiles.forEach((file) => patchPodfile(file, buildNative));
59
+ logger.info(
60
+ `[cocos-sdk] Installed native bridge (${gradleFiles.length} Android, ${podfiles.length} iOS project files).`,
61
+ );
62
+ }
63
+
64
+ function patchCocos2IosConfiguration(projectFile, target) {
65
+ const projectDirectory = path.dirname(path.dirname(projectFile));
66
+ const iosDirectory = path.join(projectDirectory, 'ios');
67
+ const configurations = ['debug', 'release'];
68
+ const configFiles = configurations.map((configuration) => ({
69
+ configuration,
70
+ file: path.join(iosDirectory, `UserConfigIOS.${configuration}.xcconfig`),
71
+ }));
72
+ if (!configFiles.some(({ file }) => fs.existsSync(file))) return;
73
+
74
+ configFiles.forEach(({ configuration, file }) => {
75
+ if (!fs.existsSync(file)) return;
76
+ replaceMarkedBlock(file, [
77
+ XCCONFIG_BEGIN,
78
+ `#include? "../Pods/Target Support Files/Pods-${target}/Pods-${target}.${configuration}.xcconfig"`,
79
+ `OTHER_LDFLAGS = $(inherited) ${cocos2CompatibilityLinkerFlags()}`,
80
+ XCCONFIG_END,
81
+ ].join('\n'), XCCONFIG_BEGIN, XCCONFIG_END, [
82
+ [LEGACY_XCCONFIG_BEGIN, LEGACY_XCCONFIG_END],
83
+ ]);
84
+ });
85
+
86
+ const original = fs.readFileSync(projectFile, 'utf8');
87
+ let next = quoteWhitespaceProductNames(original).replace(
88
+ /(\b(?:HEADER|LIBRARY)_SEARCH_PATHS\s*=\s*)"([^"]*)";/g,
89
+ (line, prefix, value) => value.includes('$(inherited)')
90
+ ? line
91
+ : `${prefix}"${`$(inherited) ${value}`.trim()}";`,
92
+ );
93
+ next = next.replace(
94
+ /(\bIPHONEOS_DEPLOYMENT_TARGET\s*=\s*)(\d+(?:\.\d+)*)(\s*;)/g,
95
+ (line, prefix, version, suffix) => compareVersions(version, '12.0') < 0
96
+ ? `${prefix}12.0${suffix}`
97
+ : line,
98
+ );
99
+ if (next !== original) fs.writeFileSync(projectFile, next);
100
+ }
101
+
102
+ function quoteWhitespaceProductNames(contents) {
103
+ return contents.replace(
104
+ /^([ \t]*productName[ \t]*=)([^;\r\n]*)(;)$/gm,
105
+ (line, prefix, value, suffix) => {
106
+ const productName = value.trim();
107
+ if (!/[ \t]/.test(productName) || (productName.startsWith('"') && productName.endsWith('"'))) {
108
+ return line;
109
+ }
110
+ const spacing = value.match(/^[ \t]*/)?.[0] || ' ';
111
+ return `${prefix}${spacing}"${productName.replace(/"/g, '\\"')}"${suffix}`;
112
+ },
113
+ );
114
+ }
115
+
116
+ function cocos2CompatibilityLinkerFlags() {
117
+ const flags = ['-lwebp'];
118
+ if (process.platform !== 'darwin') return flags.join(' ');
119
+ try {
120
+ const version = execFileSync('xcodebuild', ['-version'], { encoding: 'utf8' });
121
+ const major = Number((version.match(/^Xcode\s+(\d+)/m) || [])[1]);
122
+ if (major >= 15) flags.push('-Wl,-ld_classic');
123
+ } catch {
124
+ // Xcode is optional when only generating or testing non-iOS projects.
125
+ }
126
+ return flags.join(' ');
127
+ }
128
+
129
+ function patchGradleProperties(file) {
130
+ let contents = fs.readFileSync(file, 'utf8');
131
+ contents = raiseNumericProperty(contents, 'PROP_COMPILE_SDK_VERSION', 34);
132
+ contents = raiseNumericProperty(contents, 'PROP_MIN_SDK_VERSION', 21);
133
+ contents = raiseNumericProperty(contents, 'PROP_TARGET_SDK_VERSION', 34);
134
+ contents = raiseVersionProperty(contents, 'PROP_BUILD_TOOLS_VERSION', '34.0.0');
135
+ contents = enableBooleanProperty(contents, 'android.useAndroidX');
136
+ if (contents !== fs.readFileSync(file, 'utf8')) fs.writeFileSync(file, contents);
137
+ }
138
+
139
+ function findNativeAppGradleFiles(propertiesFile) {
140
+ const contents = fs.readFileSync(propertiesFile, 'utf8');
141
+ const nativeDirectoryValue = readProperty(contents, 'NATIVE_DIR');
142
+ if (!nativeDirectoryValue) return [];
143
+ const nativeDirectory = path.isAbsolute(nativeDirectoryValue)
144
+ ? nativeDirectoryValue
145
+ : path.resolve(path.dirname(propertiesFile), nativeDirectoryValue);
146
+ const gradleFile = path.join(nativeDirectory, 'app', 'build.gradle');
147
+ return fs.existsSync(gradleFile) ? [gradleFile] : [];
148
+ }
149
+
150
+ function readProperty(contents, key) {
151
+ const match = contents.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*(.+?)\\s*$`, 'm'));
152
+ return match && match[1] ? match[1].trim() : null;
153
+ }
154
+
155
+ function uniqueFiles(files) {
156
+ return [...new Set(files.map((file) => path.resolve(file)))];
157
+ }
158
+
159
+ function enableBooleanProperty(contents, key) {
160
+ const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(?:true|false)(\\s*)$`, 'mi');
161
+ if (pattern.test(contents)) {
162
+ return contents.replace(pattern, (line, prefix, suffix) => `${prefix}true${suffix}`);
163
+ }
164
+ return `${contents.replace(/\s*$/, '')}\n${key}=true\n`;
165
+ }
166
+
167
+ function raiseNumericProperty(contents, key, minimum) {
168
+ const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(-?\\d+)(\\s*)$`, 'm');
169
+ return contents.replace(pattern, (line, prefix, value, suffix) => (
170
+ Number(value) < minimum ? `${prefix}${minimum}${suffix}` : line
171
+ ));
172
+ }
173
+
174
+ function raiseVersionProperty(contents, key, minimum) {
175
+ const pattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)(\\d+(?:\\.\\d+)*)(\\s*)$`, 'm');
176
+ return contents.replace(pattern, (line, prefix, value, suffix) => (
177
+ compareVersions(value, minimum) < 0 ? `${prefix}${minimum}${suffix}` : line
178
+ ));
179
+ }
180
+
181
+ function compareVersions(left, right) {
182
+ const leftParts = left.split('.').map(Number);
183
+ const rightParts = right.split('.').map(Number);
184
+ const length = Math.max(leftParts.length, rightParts.length);
185
+ for (let index = 0; index < length; index += 1) {
186
+ const difference = (leftParts[index] || 0) - (rightParts[index] || 0);
187
+ if (difference !== 0) return difference;
188
+ }
189
+ return 0;
190
+ }
191
+
192
+ function patchGradle(file, nativeRoot) {
193
+ const javaDir = normalize(path.join(nativeRoot, 'android', 'src', 'main', 'java'));
194
+ replaceMarkedBlock(file, [
195
+ BEGIN,
196
+ 'android {',
197
+ ` sourceSets { main.java.srcDirs += ['${escapeGroovy(javaDir)}'] }`,
198
+ '}',
199
+ 'repositories {',
200
+ " maven { url 'https://mvnrepo.guance.com/repository/maven-releases' }",
201
+ '}',
202
+ 'dependencies {',
203
+ " implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-sdk:1.7.6-alpha01'",
204
+ " implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-native:1.1.3'",
205
+ " implementation 'com.cloudcare.ft.mobile.sdk.tracker.agent:ft-session-replay:0.1.9-alpha01'",
206
+ " implementation 'com.google.code.gson:gson:2.10.1'",
207
+ " implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.22')",
208
+ " implementation 'androidx.appcompat:appcompat:1.1.0'",
209
+ " implementation 'androidx.fragment:fragment:1.8.0'",
210
+ '}',
211
+ END,
212
+ ].join('\n'), BEGIN, END, [[LEGACY_BEGIN, LEGACY_END]]);
213
+ }
214
+
215
+ function patchPodfile(file, nativeRoot) {
216
+ const iosDir = normalize(path.join(nativeRoot, 'ios'));
217
+ const block = [
218
+ POD_BEGIN,
219
+ `pod 'FTCocosBridge', :path => '${escapeRuby(iosDir)}'`,
220
+ POD_END,
221
+ ].join('\n');
222
+ const original = fs.readFileSync(file, 'utf8');
223
+ const currentPattern = markedPattern(POD_BEGIN, POD_END);
224
+ const legacyPodPattern = markedPattern(LEGACY_POD_BEGIN, LEGACY_POD_END);
225
+ const legacyPattern = markedPattern(LEGACY_BEGIN, LEGACY_END);
226
+ let next;
227
+ if (currentPattern.test(original)) {
228
+ next = replaceIndentedMarkedBlock(original, POD_BEGIN, POD_END, block);
229
+ } else if (legacyPodPattern.test(original)) {
230
+ next = replaceIndentedMarkedBlock(original, LEGACY_POD_BEGIN, LEGACY_POD_END, block);
231
+ } else if (legacyPattern.test(original)) {
232
+ next = replaceIndentedMarkedBlock(original, LEGACY_BEGIN, LEGACY_END, block);
233
+ } else {
234
+ const targetPattern = /(^[ \t]*target\s+['"][^'"]+['"]\s+do\s*$)/m;
235
+ next = targetPattern.test(original)
236
+ ? original.replace(targetPattern, `$1\n ${block.replace(/\n/g, '\n ')}`)
237
+ : `${original.replace(/\s*$/, '')}\n\n${block}\n`;
238
+ }
239
+ if (next !== original) fs.writeFileSync(file, next);
240
+ }
241
+
242
+ function replaceIndentedMarkedBlock(contents, begin, end, block) {
243
+ const pattern = new RegExp(`(^[\\t ]*)${escapeRegExp(begin)}[\\s\\S]*?${escapeRegExp(end)}`, 'm');
244
+ return contents.replace(pattern, (match, indent) => `${indent}${block.replace(/\n/g, `\n${indent}`)}`);
245
+ }
246
+
247
+ function findIosApplicationTarget(projectFile) {
248
+ const contents = fs.readFileSync(projectFile, 'utf8');
249
+ const nativeTarget = /\/\* ([^*]+) \*\/ = \{\s*isa = PBXNativeTarget;([\s\S]*?)\n\s*\};/g;
250
+ const targets = [];
251
+ let match;
252
+ while ((match = nativeTarget.exec(contents))) {
253
+ if (!/productType = ["']?com\.apple\.product-type\.application["']?;/.test(match[2])) continue;
254
+ const nameMatch = match[2].match(/\n\s*name = ("(?:[^"\\]|\\.)*"|[^;]+);/);
255
+ targets.push(unquotePbxValue(nameMatch ? nameMatch[1] : match[1]));
256
+ }
257
+ return targets.find((target) => /(?:^|[-_.])mobile$/i.test(target))
258
+ || targets.find((target) => /(?:^|[-_.])ios(?:$|[-_.])/i.test(target))
259
+ || targets[0]
260
+ || null;
261
+ }
262
+
263
+ function unquotePbxValue(value) {
264
+ const trimmed = value.trim();
265
+ return trimmed.startsWith('"') && trimmed.endsWith('"')
266
+ ? trimmed.slice(1, -1).replace(/\\"/g, '"')
267
+ : trimmed;
268
+ }
269
+
270
+ function createPodfile(file, projectFile, target) {
271
+ const projectName = path.basename(path.dirname(projectFile));
272
+ fs.writeFileSync(file, [
273
+ "platform :ios, '12.0'",
274
+ `project '${escapeRuby(projectName)}'`,
275
+ '',
276
+ `target '${escapeRuby(target)}' do`,
277
+ 'end',
278
+ '',
279
+ ].join('\n'));
280
+ }
281
+
282
+ function replaceMarkedBlock(file, block, begin = BEGIN, end = END, legacyMarkers = []) {
283
+ const original = fs.readFileSync(file, 'utf8');
284
+ const pattern = markedPattern(begin, end);
285
+ let next;
286
+ if (pattern.test(original)) {
287
+ next = original.replace(pattern, block);
288
+ } else {
289
+ const legacy = legacyMarkers.find(([legacyBegin, legacyEnd]) => (
290
+ markedPattern(legacyBegin, legacyEnd).test(original)
291
+ ));
292
+ next = legacy
293
+ ? original.replace(markedPattern(legacy[0], legacy[1]), block)
294
+ : `${original.replace(/\s*$/, '')}\n\n${block}\n`;
295
+ }
296
+ if (next !== original) fs.writeFileSync(file, next);
297
+ }
298
+
299
+ function markedPattern(begin, end) {
300
+ return new RegExp(`${escapeRegExp(begin)}[\\s\\S]*?${escapeRegExp(end)}`, 'm');
301
+ }
302
+
303
+ function copyDirectory(source, destination) {
304
+ fs.mkdirSync(destination, { recursive: true });
305
+ for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
306
+ const from = path.join(source, entry.name);
307
+ const to = path.join(destination, entry.name);
308
+ if (entry.isDirectory()) copyDirectory(from, to);
309
+ else fs.copyFileSync(from, to);
310
+ }
311
+ }
312
+
313
+ function findFiles(root, maxDepth) {
314
+ const result = [];
315
+ function visit(directory, depth) {
316
+ if (depth > maxDepth) return;
317
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
318
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
319
+ const child = path.join(directory, entry.name);
320
+ if (entry.isDirectory()) visit(child, depth + 1);
321
+ else result.push(child);
322
+ }
323
+ }
324
+ visit(root, 0);
325
+ return result;
326
+ }
327
+
328
+ function normalize(value) { return value.split(path.sep).join('/'); }
329
+ function escapeGroovy(value) { return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); }
330
+ function escapeRuby(value) { return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'"); }
331
+ function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
332
+
333
+ module.exports = { installNative };
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { installNative } = require('./install-native.cjs');
5
+
6
+ function onBuildFinished(options, callback) {
7
+ try {
8
+ installNative(options && (options.dest || options.buildPath), __dirname, Editor);
9
+ callback();
10
+ } catch (error) {
11
+ Editor.error(`[cocos-sdk] ${error && error.stack ? error.stack : error}`);
12
+ callback(error);
13
+ }
14
+ }
15
+
16
+ module.exports = {
17
+ load() {
18
+ Editor.Builder.on('build-finished', onBuildFinished);
19
+ },
20
+ unload() {
21
+ Editor.Builder.removeListener('build-finished', onBuildFinished);
22
+ },
23
+ };
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "guance-cocos-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Observability SDK native build integration for Cocos Creator",
5
+ "main": "main.js"
6
+ }
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ exports.load = function load() {};
4
+ exports.unload = function unload() {};
5
+ exports.configs = {
6
+ '*': {
7
+ hooks: './hooks',
8
+ },
9
+ };