stim 1.20.2 → 1.22.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 (231) hide show
  1. package/README.md +141 -8
  2. package/dist/acquire-artifact-Co2k4f7O.mjs +171 -0
  3. package/dist/act-DsuqEkiM.mjs +2801 -0
  4. package/dist/activity-CMLmzp7o.mjs +1397 -0
  5. package/dist/{agent-device-usage-output-Dzgv6lgR.mjs → agent-device-usage-output-DUFaTMdd.mjs} +23 -67
  6. package/dist/{android-DCKZrNvV.mjs → android-ByRMUoiJ.mjs} +157 -93
  7. package/dist/{android-Mz_Inn3w.mjs → android-C7sVmyI9.mjs} +299 -116
  8. package/dist/{android-Dlzxshgp.mjs → android-DGkNqa_c.mjs} +5 -5
  9. package/dist/{android-HqP1_vB_.mjs → android-DR5lZ2Az.mjs} +2 -2
  10. package/dist/android-cas-compiler.mjs +2 -2
  11. package/dist/{android-cas-Bl-cLJBk.mjs → android-cas-ngferVq2.mjs} +7 -6
  12. package/dist/android-project-BCAAmMwz.mjs +12 -0
  13. package/dist/android-project-DVWyCbWU.d.mts +391 -0
  14. package/dist/api.d.mts +810 -64
  15. package/dist/api.mjs +782 -1
  16. package/dist/{artifact-HSwkIWEQ.mjs → artifact-8EY8SAPw.mjs} +240 -213
  17. package/dist/{artifact-D3czlUvT.mjs → artifact-DJPy518Y.mjs} +203 -164
  18. package/dist/artifact-platform-CXcmX_j3.mjs +27 -0
  19. package/dist/{browser-web-CA-F1GQo.mjs → browser-web-Bcv99PBM.mjs} +194 -64
  20. package/dist/budget-Cvwn54qV.mjs +9285 -0
  21. package/dist/{build-DYDbfkk5.mjs → build-CabC3G23.mjs} +153 -98
  22. package/dist/build-cache-Dv7RN200.mjs +602 -0
  23. package/dist/build-plan-DUC8Ka9y.mjs +248 -0
  24. package/dist/{cache-manifest-XH-fvDUj.mjs → cache-manifest-DSeQjt-Q.mjs} +2 -2
  25. package/dist/cache-manifest.mjs +1 -1
  26. package/dist/{ccache-zdKiYQ3E.mjs → ccache-Btwc36-I.mjs} +10 -9
  27. package/dist/{cdp-Dq_ypAlJ.mjs → cdp-3fwICjzi.mjs} +18 -5
  28. package/dist/{chrome-BnzZMqsR.mjs → chrome-Bbw689-6.mjs} +7 -4
  29. package/dist/{cli-CLP3diBm.mjs → cli-CHZa9Lvk.mjs} +20 -20
  30. package/dist/cli.mjs +1 -1
  31. package/dist/client-OyRoEuSr.mjs +1577 -0
  32. package/dist/collector-run.d.mts +4 -40
  33. package/dist/collector-run.mjs +9 -8
  34. package/dist/{command-output-BTy8hZ0F.mjs → command-output-gwpm28fu.mjs} +1 -1
  35. package/dist/config-DlrsduwG.mjs +955 -0
  36. package/dist/{created-devices-Dzd5C2LF.mjs → created-devices-x9rN6bhs.mjs} +14 -4
  37. package/dist/{dependency-state-DG0p31-y.mjs → dependency-state-1I9KZT1Y.mjs} +20 -5
  38. package/dist/{detached-entry-B9C_zeQC.mjs → detached-entry-BwNEtIrP.mjs} +1 -1
  39. package/dist/{dev-client-DAWVIGBu.mjs → dev-client-BSDR5h3F.mjs} +2 -2
  40. package/dist/{device-BECOiufl.mjs → device-B-L3Fbxy.mjs} +91 -34
  41. package/dist/device-DklWZLqb.mjs +1068 -0
  42. package/dist/{device-capacity-CBUAcRyQ.mjs → device-capacity-DK5_EwRS.mjs} +42 -13
  43. package/dist/device-host-worker.mjs +76 -79
  44. package/dist/{device-ios-COSi6oS1.mjs → device-ios-DoB6KFCO.mjs} +77 -51
  45. package/dist/{device-lease-run-Cw2M4z51.mjs → device-lease-run-xJPQ_QQG.mjs} +14 -26
  46. package/dist/{device-pool-Bf-pOhSw.mjs → device-pool-BMkdsefq.mjs} +5 -5
  47. package/dist/{doctor-kfMBnUw6.mjs → doctor-Bo7BXLux.mjs} +271 -320
  48. package/dist/{doctor-CB8oZKCk.mjs → doctor-D5_EzwfA.mjs} +186 -91
  49. package/dist/doctor-fingerprint-DZLoYFVb.mjs +16 -0
  50. package/dist/doctor-fingerprint.mjs +19 -0
  51. package/dist/doctor-thjWAV0z.mjs +2 -0
  52. package/dist/{doctor-watchman-BRyV2adA.mjs → doctor-watchman-N2wDotwQ.mjs} +40 -21
  53. package/dist/{eas-build-JyfqyHfC.mjs → eas-build-CwknaQYj.mjs} +53 -20
  54. package/dist/{build-plan-B7SZsc2N.mjs → eas-fallback-CSgAulr5.mjs} +41 -214
  55. package/dist/{watchman-CPQFZLXY.mjs → eas-session-ledger-DlY_serQ.mjs} +230 -11
  56. package/dist/{error-diagnostics-BR677IDM.mjs → error-diagnostics-DBWO2rxE.mjs} +172 -82
  57. package/dist/exec-DEoAhcze.mjs +858 -0
  58. package/dist/exec-DnYc4HGH.d.mts +78 -0
  59. package/dist/{gc-qWOMdnER.mjs → gc-CXxN-4SE.mjs} +1091 -1029
  60. package/dist/gc-DnNDQyaP.mjs +3 -0
  61. package/dist/{guide-G9cAbVAc.mjs → guide-Br0LEfKy.mjs} +1165 -297
  62. package/dist/{hosted-android-C3MHGld1.mjs → hosted-android-B-9f-jkd.mjs} +10 -8
  63. package/dist/{hosted-client-ZEKpS9vw.mjs → hosted-client-DZAPrcro.mjs} +34 -19
  64. package/dist/{hosted-ios-l-o3iM9J.mjs → hosted-ios-CsCS21hn.mjs} +1 -1
  65. package/dist/{hosted-logs-EzQM7-3Z.mjs → hosted-logs-FIRx9X2f.mjs} +77 -43
  66. package/dist/{hosted-macos-BACVAVqE.mjs → hosted-macos-_awYSpfv.mjs} +35 -22
  67. package/dist/{hosted-native-A4s1QPXe.mjs → hosted-native-BdzE668-.mjs} +49 -27
  68. package/dist/idle-C4cZ757K.d.mts +24 -0
  69. package/dist/{idle-shutdown-DtxhPTKe.mjs → idle-shutdown-DDg3SdvY.mjs} +11 -10
  70. package/dist/ios-CDvlmUs7.d.mts +24 -0
  71. package/dist/{ios-BwVCF7oA.mjs → ios-Ds1clbIt.mjs} +8 -8
  72. package/dist/{ios-device-D7pi2Sca.mjs → ios-device--h_-8ENa.mjs} +51 -26
  73. package/dist/{ios-device-B5veSDDQ.mjs → ios-device-BXZ0c7Kb.mjs} +1 -1
  74. package/dist/{ios-RkW4pnQf.mjs → ios-hcBpnEGk.mjs} +200 -93
  75. package/dist/{ios-Ce7bc7br.mjs → ios-pm4nL6By.mjs} +160 -108
  76. package/dist/{ios-project-K9hY_Jab.mjs → ios-project-CZhKODF3.mjs} +13 -13
  77. package/dist/ios-signing-BtAffm0A.mjs +489 -0
  78. package/dist/{ios-state-CBLe1xYw.mjs → ios-state-Dtw5K2aI.mjs} +1 -1
  79. package/dist/{ios-nOLJGVdy.mjs → ios-xtlRHaeB.mjs} +1 -1
  80. package/dist/{js-swap-Bb3nsS07.mjs → js-swap-Bwhh4S7V.mjs} +30 -25
  81. package/dist/{launch-C3qJ6Agb.mjs → launch-BjxemNpK.mjs} +85 -543
  82. package/dist/{launch-F4sOqAhB.mjs → launch-CCzXlc8r.mjs} +91 -90
  83. package/dist/logs-BfwwadsZ.mjs +479 -0
  84. package/dist/logs-jTS_lHSo.mjs +248 -0
  85. package/dist/{macos-D7uDvO-z.mjs → macos-DVlSSyUg.mjs} +1 -1
  86. package/dist/macos-NfV2D7dO.mjs +694 -0
  87. package/dist/macos-run.mjs +1 -1
  88. package/dist/maintenance-run.mjs +123 -248
  89. package/dist/{metro-DnCEjCxs.mjs → metro-DiXtA3Ty.mjs} +107 -30
  90. package/dist/metro-gateway-CKZqKqx7.mjs +209 -0
  91. package/dist/{named-ports-4WopRPg-.mjs → named-ports-DkEzOfzO.mjs} +42 -90
  92. package/dist/native-android-CqgnOgsT.mjs +645 -0
  93. package/dist/native-gradle-artifact-inputs-DHFnmrVf.mjs +270 -0
  94. package/dist/native-gradle-inputs-Dnh84Zbd.mjs +211 -0
  95. package/dist/native-inputs-TRTTTRxt.mjs +91 -0
  96. package/dist/native-run-NwUuxbkg.mjs +276 -0
  97. package/dist/{native-runtime-k8dTIrbK.mjs → native-runtime-B7KIafpM.mjs} +11 -9
  98. package/dist/native-source-Y0yLhFyQ.mjs +133 -0
  99. package/dist/{native-xcode-inputs-CykopJdM.mjs → native-xcode-inputs-D_VOfFL7.mjs} +26 -18
  100. package/dist/{native-xcode-ios-Bbf30Gm0.mjs → native-xcode-ios-BYDOHWLN.mjs} +104 -60
  101. package/dist/{ndjson-GOnbyvso.mjs → ndjson-CgE_o3Dl.mjs} +3 -3
  102. package/dist/offload-worker.d.mts +59 -41
  103. package/dist/offload-worker.mjs +478 -115
  104. package/dist/operation-exec-BW0em61G.mjs +171 -0
  105. package/dist/{ownership-DCtw_2IA.mjs → ownership-C5fo5Edb.mjs} +3 -3
  106. package/dist/{page-DRHy329N.mjs → page-DBL2PiUU.mjs} +12 -5
  107. package/dist/paths-BsJMoPP2.mjs +12 -0
  108. package/dist/paths-DQtTgsBf.mjs +42 -0
  109. package/dist/{placement-log-MOfPVgaM.mjs → placement-log-BnGgJRRZ.mjs} +5 -5
  110. package/dist/{plan-placement-V0TdzYXp.mjs → plan-placement-DIsMtN-d.mjs} +15 -11
  111. package/dist/{ports-DdSUicVo.mjs → ports-Cy1RkmuQ.mjs} +3 -3
  112. package/dist/prebuild-D4JoEAEs.mjs +484 -0
  113. package/dist/{project-_phNIJfs.mjs → project-wM_XFTvE.mjs} +65 -37
  114. package/dist/{pull-request-CQ8sPbZa.mjs → pull-request-W1IuLXDt.mjs} +102 -20
  115. package/dist/pull-request-eODyIqZF.d.mts +124 -0
  116. package/dist/pull-requests.d.mts +2 -120
  117. package/dist/pull-requests.mjs +2 -2
  118. package/dist/{react-native-android-CM1XRDwv.mjs → react-native-android-6OZ7MSM7.mjs} +121 -72
  119. package/dist/{gradle-DSrXb6lG.mjs → react-native-build-Dvd8hC21.mjs} +292 -15
  120. package/dist/react-native-doctor-DsoSF1Y9.mjs +234 -0
  121. package/dist/{react-native-ios-Dhq_eiYQ.mjs → react-native-ios-4u1Rn-GR.mjs} +71 -39
  122. package/dist/{recordings-D0d5aQt0.mjs → recordings-CQmfzAh7.mjs} +12 -9
  123. package/dist/registration-BcRgF6Ox.mjs +51 -0
  124. package/dist/{reload-C8JhxjSh.mjs → reload-BzkYabB-.mjs} +94 -47
  125. package/dist/reload-D7AVlb8N.mjs +2 -0
  126. package/dist/{remote-BiR6aYjy.mjs → remote-DjGDmlTZ.mjs} +26 -18
  127. package/dist/result-D2Ykz_iD.mjs +435 -0
  128. package/dist/{run-BtPgpKks.mjs → run-DidHghD1.mjs} +5 -5
  129. package/dist/selection-DSMbWEX2.mjs +620 -0
  130. package/dist/{server-bare-R2m_gsH8.mjs → server-bare-CafzuyFB.mjs} +3 -4
  131. package/dist/{server-command-CTtCkmcQ.mjs → server-command-C6QjeupS.mjs} +14 -7
  132. package/dist/{server-expo-DsguMGUF.mjs → server-expo-CrjB29pq.mjs} +54 -11
  133. package/dist/server-expo-D58c9L0M.mjs +2 -0
  134. package/dist/{settings-B717odTD.mjs → settings-C7O8A6ZI.mjs} +309 -119
  135. package/dist/settings-DpR-1Wnn.mjs +114 -0
  136. package/dist/settings-write-CzD60rOD.mjs +360 -0
  137. package/dist/settings.schema.json +176 -16
  138. package/dist/{simslim-CCr3rE-A.mjs → simslim-BNckWpXi.mjs} +14 -12
  139. package/dist/{slot-launch-DPt0m9Nd.mjs → slot-launch-CbfmNgM6.mjs} +15 -20
  140. package/dist/{spawn-entry-Dcb7sDUz.mjs → spawn-entry-jw19m8Nl.mjs} +0 -1
  141. package/dist/stage-Bps5oius.mjs +200 -0
  142. package/dist/{start-TXeMmmO2.mjs → start-Br-oxqMD.mjs} +1 -1
  143. package/dist/start-EojN4WFz.mjs +1364 -0
  144. package/dist/{state-D1Icyjlu.mjs → state--smjFSTL.mjs} +55 -13
  145. package/dist/{state-CG_OFoaA.mjs → state-08I3hw3_.mjs} +3 -2
  146. package/dist/{stats-BoY5sEPU.mjs → stats-D3GerlFW.mjs} +7 -13
  147. package/dist/stats-report-BzaPrRm6.mjs +16 -0
  148. package/dist/{status-BTA7kKiQ.mjs → status-BRROykC8.mjs} +7 -5
  149. package/dist/status-EvrK72L2.mjs +2 -0
  150. package/dist/{status-WgFbkRzj.mjs → status-WBDajew2.mjs} +554 -452
  151. package/dist/{status-watch-C23ILtf9.mjs → status-watch-Bg_u-pwR.mjs} +222 -25
  152. package/dist/status-worker.d.mts +1 -0
  153. package/dist/status-worker.mjs +19 -0
  154. package/dist/stim-desktop-D5OGpYZM.mjs +112 -0
  155. package/dist/{stop-DR6VoDIk.mjs → stop-DTZ9uTw3.mjs} +2 -2
  156. package/dist/{stop-DPEhunlw.mjs → stop-Dky10AEJ.mjs} +33 -23
  157. package/dist/{stop-BNmBMi1F.mjs → stop-Mv6W9FAk.mjs} +137 -98
  158. package/dist/supervisor-run.d.mts +8 -17
  159. package/dist/supervisor-run.mjs +56 -28
  160. package/dist/{support-CwjbFs9H.mjs → support-CNioewsd.mjs} +14 -14
  161. package/dist/{support-DMTqj3Hm.mjs → support-yUiOjnVY.mjs} +20 -13
  162. package/dist/swiftpm-artifact-inputs-DFcGsXDP.mjs +153 -0
  163. package/dist/swiftpm-macos-BIak-Rxv.mjs +532 -0
  164. package/dist/toolchain-BY8X8HXx.mjs +2 -0
  165. package/dist/toolchain-DpJMHq0n.mjs +876 -0
  166. package/dist/{trigger-CigAYjeL.mjs → trigger-Cbyc41d_.mjs} +21 -6
  167. package/dist/trigger-yb_nFzPF.mjs +2 -0
  168. package/dist/{warm-progress-BuY-Fvfn.mjs → warm-progress-CA3TgT3-.mjs} +263 -156
  169. package/dist/web-CZ07gd77.mjs +2 -0
  170. package/dist/{web-BDBMxDpx.mjs → web-DKx6yoFA.mjs} +20 -14
  171. package/dist/web-run.mjs +13 -12
  172. package/dist/windows-report.d.mts +1 -0
  173. package/dist/windows-report.mjs +18 -0
  174. package/dist/windows-report.ps1 +43 -0
  175. package/dist/{workspace-state-DJt_MMvf.mjs → workspace-state-U08dEzhG.mjs} +62 -58
  176. package/dist/{workspaces-C36s2jb9.mjs → workspaces-CpANmBlq.mjs} +1723 -1286
  177. package/dist/{worktree-CgvJYJ-Q.mjs → worktree-CHecZ4Oq.mjs} +1097 -547
  178. package/dist/worktree-ZqZVjD9K.mjs +2 -0
  179. package/dist/xcode-BXn9-xYx.mjs +896 -0
  180. package/package.json +7 -5
  181. package/shim/android-audio/Main.java +24 -0
  182. package/shim/android-audio/README.md +17 -0
  183. package/shim/android-audio.jar +0 -0
  184. package/shim/android-optimizations.gradle +7 -5
  185. package/dist/activity-BSV745Kz.mjs +0 -629
  186. package/dist/api-qvOzWyfO.mjs +0 -154
  187. package/dist/api-run.mjs +0 -294
  188. package/dist/app-install-BIKtMfPq.mjs +0 -896
  189. package/dist/artifact-lifecycle-DzPpBYvK.mjs +0 -30
  190. package/dist/budget-f7516Zk0.mjs +0 -4106
  191. package/dist/build-facts-DcLv2HSd.d.mts +0 -111
  192. package/dist/cancellation-C_22VQTH.mjs +0 -24
  193. package/dist/client-qQAaXSUs.mjs +0 -1771
  194. package/dist/config-BYDxlMY3.mjs +0 -562
  195. package/dist/device-DuiPJQSn.mjs +0 -290
  196. package/dist/device-lease-BX1sJQ2E.mjs +0 -1224
  197. package/dist/device-remote-xRT0Vmo9.mjs +0 -1272
  198. package/dist/eas-session-ledger-Cm0Gwq2F.mjs +0 -207
  199. package/dist/exec-DqKo9GKJ.mjs +0 -268
  200. package/dist/git-DDfFzkMm.mjs +0 -45
  201. package/dist/launch-verify-B6Q8hZP-.mjs +0 -428
  202. package/dist/logs-BGrEUaEs.mjs +0 -383
  203. package/dist/macos-Ch5VJmcS.mjs +0 -584
  204. package/dist/metro-gateway-CX9Xlkq2.mjs +0 -103
  205. package/dist/miss-reason-mKzZ4VvN.mjs +0 -238
  206. package/dist/native-android-D5qc3-_v.mjs +0 -226
  207. package/dist/native-gradle-inputs-BsLRrl7u.mjs +0 -349
  208. package/dist/ndjson-Du3j0AQ9.d.mts +0 -17
  209. package/dist/plan-C4TjdPsR.mjs +0 -260
  210. package/dist/prebuild-DYbucPXy.mjs +0 -212
  211. package/dist/preview-78a9kR_-.mjs +0 -1011
  212. package/dist/react-native-build-CtCccJtb.mjs +0 -239
  213. package/dist/react-native-doctor-CfRnFfjs.mjs +0 -78
  214. package/dist/remote-cache-OyOyVIS3.mjs +0 -526
  215. package/dist/result-CaJg5Iat.mjs +0 -186
  216. package/dist/server-expo-Bigriskl.mjs +0 -2
  217. package/dist/settings-BORNaaCO.mjs +0 -402
  218. package/dist/settings-vk3mJGSm.d.mts +0 -13
  219. package/dist/spawn-claims-DVS5RkMS.mjs +0 -72
  220. package/dist/stage-KNTQopqv.mjs +0 -157
  221. package/dist/start-BWqzODpb.mjs +0 -1116
  222. package/dist/stim-desktop-BzBN2Em2.mjs +0 -63
  223. package/dist/swiftpm-macos-DRNVJWlb.mjs +0 -119
  224. package/dist/tailnet-Dh-qiYzG.mjs +0 -265
  225. package/dist/toolchain-BFkAcstd.mjs +0 -2
  226. package/dist/toolchain-DxSsNssu.mjs +0 -1657
  227. package/dist/trigger-9_USgmxz.mjs +0 -2
  228. package/dist/web-Dq-i3wzJ.mjs +0 -2
  229. package/dist/worktree-DpLdCHga.mjs +0 -2
  230. package/dist/{api-run.d.mts → doctor-fingerprint.d.mts} +0 -0
  231. package/dist/{errors-DzkMYh8Q.mjs → errors-ccaPc4ox.mjs} +2 -2
@@ -0,0 +1,270 @@
1
+ import { t as getExecutor } from "./exec-DEoAhcze.mjs";
2
+ import { r as childEnvironment } from "./operation-exec-BW0em61G.mjs";
3
+ import { n as buildCacheKey } from "./build-cache-Dv7RN200.mjs";
4
+ import { o as androidHome } from "./android-C7sVmyI9.mjs";
5
+ import { n as fingerprintNativeInputs } from "./native-inputs-TRTTTRxt.mjs";
6
+ import { r as nativeGradleLocalSourceDigest, t as gradleOffloadInputs } from "./native-gradle-inputs-Dnh84Zbd.mjs";
7
+ import { createHash } from "node:crypto";
8
+ import { homedir } from "node:os";
9
+ import { dirname, join, resolve } from "node:path";
10
+ import { readFile, readdir, realpath, stat } from "node:fs/promises";
11
+ //#region src/integrations/native-gradle-artifact-inputs.ts
12
+ const NATIVE_GRADLE_CACHE_LIMIT = "Native APK caching requires android.artifactInputs with complete: true and a complete declaration of repeatable pinned inputs. Gradle incremental and task-cache reuse remain available without it.";
13
+ function nativeGradleWorkerScope(sourceDigest, inputs) {
14
+ return JSON.stringify([sourceDigest, {
15
+ complete: true,
16
+ ignored: inputs.ignored,
17
+ outputs: inputs.outputs
18
+ }]);
19
+ }
20
+ function nativeGradleWorkerArtifactIdentity(fingerprint, scope, variant, abi) {
21
+ const hash = createHash("sha256").update(JSON.stringify([
22
+ "stim-native-gradle-worker-v1",
23
+ fingerprint,
24
+ scope
25
+ ])).digest("hex");
26
+ return {
27
+ hash,
28
+ key: buildCacheKey("android", hash, {
29
+ variant,
30
+ ...abi ? { abi } : {}
31
+ })
32
+ };
33
+ }
34
+ function gradleArtifactInputs(value) {
35
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(NATIVE_GRADLE_CACHE_LIMIT);
36
+ const localFiles = "localFiles" in value ? value.localFiles : [];
37
+ const environment = "environment" in value ? value.environment : [];
38
+ if (Object.keys(value).some((key) => ![
39
+ "complete",
40
+ "ignored",
41
+ "outputs",
42
+ "localFiles",
43
+ "environment"
44
+ ].includes(key)) || !Array.isArray(localFiles) || !localFiles.every((path) => typeof path === "string" && path.length > 0 && !path.includes("\0")) || !Array.isArray(environment) || !environment.every((name) => typeof name === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(name))) throw new Error(NATIVE_GRADLE_CACHE_LIMIT);
45
+ let inventory;
46
+ try {
47
+ inventory = gradleOffloadInputs({
48
+ complete: "complete" in value ? value.complete : void 0,
49
+ ignored: "ignored" in value ? value.ignored : void 0,
50
+ outputs: "outputs" in value ? value.outputs : void 0
51
+ });
52
+ } catch (error) {
53
+ throw new Error(String(error).replaceAll("android.offloadInputs", "android.artifactInputs"), { cause: error });
54
+ }
55
+ return {
56
+ ...inventory,
57
+ localFiles: [...new Set(localFiles)].toSorted(),
58
+ environment: [...new Set(environment)].toSorted()
59
+ };
60
+ }
61
+ async function optionalText(path, signal, encoding = "utf8") {
62
+ try {
63
+ return await readFile(path, {
64
+ encoding,
65
+ signal
66
+ });
67
+ } catch (error) {
68
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
69
+ throw error;
70
+ }
71
+ }
72
+ async function javaRelease(env, signal) {
73
+ let home = env.JAVA_HOME;
74
+ if (!home) {
75
+ const java = getExecutor().findExecutable("java");
76
+ if (java) {
77
+ const selected = dirname(dirname(await realpath(java)));
78
+ if ((await optionalText(join(selected, "release"), signal))?.includes("JAVA_VERSION=")) home = selected;
79
+ }
80
+ }
81
+ if (!home && process.platform === "darwin") {
82
+ const child = childEnvironment(env);
83
+ home = (await getExecutor().runFileAsync("/usr/libexec/java_home", [], {
84
+ timeoutMs: 1e4,
85
+ signal,
86
+ ...child
87
+ })).trim();
88
+ }
89
+ if (!home || !(await optionalText(join(home, "release"), signal))?.includes("JAVA_VERSION=")) throw new Error("The Gradle wrapper JDK release identity is unavailable.");
90
+ return join(home, "release");
91
+ }
92
+ async function localPropertiesIdentity(properties, sdk, root, signal) {
93
+ const content = await optionalText(properties, signal, "latin1");
94
+ if (content === null) return null;
95
+ const retained = [];
96
+ let selected = null;
97
+ for (const [, line = "", ending = ""] of content.matchAll(/([^\r\n]*)(\r\n|\r|\n|$)/g)) {
98
+ if (/^[ \t\f]*$/.test(line) || /^[ \t\f]*[#!]/.test(line)) {
99
+ retained.push(line + ending);
100
+ continue;
101
+ }
102
+ if ((line.match(/\\+$/)?.[0].length ?? 0) % 2 !== 0) throw new Error("Native APK caching requires single-line local.properties values.");
103
+ const entry = /^[ \t\f]*([A-Za-z0-9_.-]+)(?:[ \t\f]*[:=][ \t\f]*|[ \t\f]+)(.*)$/.exec(line);
104
+ if (!entry) {
105
+ if (/^[ \t\f]*[A-Za-z0-9_.-]+[ \t\f]*$/.test(line) && line.trim() !== "sdk.dir") {
106
+ retained.push(line + ending);
107
+ continue;
108
+ }
109
+ throw new Error("Native APK caching requires plain, unescaped local.properties keys.");
110
+ }
111
+ if (entry[1] !== "sdk.dir") {
112
+ retained.push(line + ending);
113
+ continue;
114
+ }
115
+ const value = entry[2] ?? "";
116
+ if (!value || [...value].some((character) => character.charCodeAt(0) > 127)) throw new Error("Native APK caching cannot resolve the local.properties SDK.");
117
+ selected = value.replace(/\\u([a-fA-F\d]{4})|\\(.)/g, (full, hex, escaped) => {
118
+ if (hex) return String.fromCharCode(parseInt(hex, 16));
119
+ if (escaped === "u") throw new Error("Native APK caching cannot resolve the local.properties SDK.");
120
+ if (escaped === "t") return " ";
121
+ if (escaped === "r") return "\r";
122
+ if (escaped === "n") return "\n";
123
+ if (escaped === "f") return "\f";
124
+ return escaped ?? full;
125
+ });
126
+ }
127
+ if (selected !== null && await realpath(resolve(root, selected)) !== sdk) throw new Error("Native APK caching requires the local.properties SDK to match ANDROID_HOME.");
128
+ return retained.join("");
129
+ }
130
+ async function nativeGradleArtifactSnapshot(root, value, build, abi, env, signal) {
131
+ signal?.throwIfAborted();
132
+ const declaration = gradleArtifactInputs(value);
133
+ const localFiles = declaration.localFiles.map((file) => resolve(root, file));
134
+ const properties = join(root, "local.properties");
135
+ const { complete, ignored, outputs } = declaration;
136
+ return nativeGradleArtifactSnapshotFromReceipt(root, {
137
+ source: await nativeGradleLocalSourceDigest(root, {
138
+ complete,
139
+ ignored,
140
+ outputs
141
+ }, [properties, ...localFiles], signal),
142
+ declaration,
143
+ build: {
144
+ variant: build.variant,
145
+ compilerCache: build.compilerCache,
146
+ gradleBuildCache: build.gradleBuildCache,
147
+ pch: build.pch,
148
+ cas: build.cas
149
+ },
150
+ abi
151
+ }, env, signal);
152
+ }
153
+ /** Revalidates private inputs; the caller must bind the receipt to a verified completed source snapshot. */
154
+ async function nativeGradleArtifactSnapshotFromReceipt(root, receipt, env, signal) {
155
+ signal?.throwIfAborted();
156
+ const { build, abi } = receipt;
157
+ if (!/^[a-f0-9]{64}$/.test(receipt.source)) throw new Error("The completed Gradle source identity is invalid.");
158
+ const declaration = gradleArtifactInputs(receipt.declaration);
159
+ const localFiles = declaration.localFiles.map((file) => resolve(root, file));
160
+ for (const path of localFiles) {
161
+ const info = await stat(path).catch((error) => {
162
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
163
+ throw error;
164
+ });
165
+ if (info && !info.isFile()) throw new Error("android.artifactInputs.localFiles must name exact regular files.");
166
+ }
167
+ const properties = join(root, "local.properties");
168
+ const sdkDirectory = await realpath(androidHome(env));
169
+ const home = env.HOME ?? env.USERPROFILE ?? homedir();
170
+ const gradleHome = env.GRADLE_USER_HOME ?? join(home, ".gradle");
171
+ const inputs = [{
172
+ name: "jdk-release",
173
+ path: await javaRelease(env, signal),
174
+ optional: false
175
+ }, ...[
176
+ "gradle.properties",
177
+ "init.gradle",
178
+ "init.gradle.kts",
179
+ "init.d"
180
+ ].map((name) => ({
181
+ name: `gradle-user/${name}`,
182
+ path: join(gradleHome, name),
183
+ optional: true
184
+ }))];
185
+ for (const group of [
186
+ "build-tools",
187
+ "platforms",
188
+ "ndk",
189
+ "cmake"
190
+ ]) {
191
+ const directory = join(sdkDirectory, group);
192
+ const versions = await readdir(directory).catch((error) => {
193
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return [];
194
+ throw error;
195
+ });
196
+ for (const version of versions.toSorted()) {
197
+ if (!(await stat(join(directory, version))).isDirectory()) continue;
198
+ const path = join(directory, version, "source.properties");
199
+ if (await optionalText(path, signal) !== null) inputs.push({
200
+ name: `sdk/${group}/${version}`,
201
+ path,
202
+ optional: false
203
+ });
204
+ }
205
+ }
206
+ if (!inputs.some((input) => input.name.startsWith("sdk/build-tools/"))) throw new Error("Android SDK build-tools version metadata is unavailable.");
207
+ const preferences = [
208
+ join(home, ".android"),
209
+ ...env.ANDROID_USER_HOME ? [env.ANDROID_USER_HOME] : [],
210
+ ...[
211
+ "ANDROID_PREFS_ROOT",
212
+ "ANDROID_SDK_HOME",
213
+ "TEST_TMPDIR"
214
+ ].flatMap((name) => env[name] ? [join(env[name], ".android")] : [])
215
+ ];
216
+ for (const [index, directory] of [...new Set(preferences)].entries()) inputs.push({
217
+ name: `debug-keystore/${index}`,
218
+ path: join(directory, "debug.keystore"),
219
+ optional: true
220
+ });
221
+ for (const [index, path] of localFiles.entries()) inputs.push({
222
+ name: `local/${index}`,
223
+ path,
224
+ optional: true
225
+ });
226
+ const environment = Object.fromEntries([.../* @__PURE__ */ new Set([
227
+ ...declaration.environment,
228
+ "JAVA_OPTS",
229
+ "JAVA_TOOL_OPTIONS",
230
+ "_JAVA_OPTIONS",
231
+ "GRADLE_OPTS"
232
+ ])].toSorted().map((name) => [name, env[name] ?? null]));
233
+ const localProperties = await localPropertiesIdentity(properties, sdkDirectory, root, signal);
234
+ const local = await fingerprintNativeInputs(inputs, {
235
+ parameters: {
236
+ declaration,
237
+ environment,
238
+ localProperties: createHash("sha256").update(JSON.stringify(localProperties)).digest("hex")
239
+ },
240
+ signal
241
+ });
242
+ const hash = createHash("sha256").update("stim-native-gradle-artifact-v1\0").update(JSON.stringify({
243
+ source: receipt.source,
244
+ local: local.hash,
245
+ platform: process.platform,
246
+ arch: process.arch,
247
+ variant: build.variant ?? "debug",
248
+ compilerCache: build.compilerCache,
249
+ gradleBuildCache: build.gradleBuildCache,
250
+ pch: build.pch,
251
+ cas: build.cas,
252
+ abi
253
+ })).digest("hex");
254
+ return {
255
+ hash,
256
+ key: buildCacheKey("android", hash, {
257
+ variant: build.variant ?? "debug",
258
+ ...abi ? { abi } : {}
259
+ }),
260
+ sdkDirectory,
261
+ receipt: {
262
+ source: receipt.source,
263
+ declaration,
264
+ build,
265
+ abi
266
+ }
267
+ };
268
+ }
269
+ //#endregion
270
+ export { nativeGradleWorkerArtifactIdentity as a, nativeGradleArtifactSnapshotFromReceipt as i, gradleArtifactInputs as n, nativeGradleWorkerScope as o, nativeGradleArtifactSnapshot as r, NATIVE_GRADLE_CACHE_LIMIT as t };
@@ -0,0 +1,211 @@
1
+ import { s as gitAsync } from "./operation-exec-BW0em61G.mjs";
2
+ import { n as fingerprintNativeInputs, r as manifestDigest } from "./native-inputs-TRTTTRxt.mjs";
3
+ import { a as sourceManifest, i as nativeTransferManifest, r as nativeFileDigest } from "./native-source-Y0yLhFyQ.mjs";
4
+ import { createHash } from "node:crypto";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { access, lstat, readFile, readlink, realpath } from "node:fs/promises";
7
+ //#region src/integrations/native-gradle-inputs.ts
8
+ function containedPath(path) {
9
+ return typeof path === "string" && path.length > 0 && !path.includes("\\") && !path.includes(":") && !path.includes("\0") && !path.split("/").some((part) => !part || part === "." || part === ".." || part.toLowerCase() === ".git");
10
+ }
11
+ function gradleOffloadInputs(value) {
12
+ const input = value;
13
+ if (!input || typeof input !== "object" || input.complete !== true || Object.keys(input).some((key) => ![
14
+ "complete",
15
+ "ignored",
16
+ "outputs"
17
+ ].includes(key)) || !Array.isArray(input.ignored) || !input.ignored.every(containedPath) || !Array.isArray(input.outputs) || !input.outputs.every(containedPath)) throw new Error("Native Gradle offload requires android.offloadInputs with complete: true, ignored: [exact repository-relative files], and outputs: [generated repository-relative directories].");
18
+ const ignored = [...new Set(input.ignored)].toSorted();
19
+ const outputs = [...new Set(input.outputs)].toSorted();
20
+ if (ignored.some((path) => path.split("/").at(-1) === "local.properties")) throw new Error("local.properties is machine-local; remove it from android.offloadInputs.ignored.");
21
+ if (outputs.some((path) => path.split("/").some((part) => part === ".gradle" || part === ".kotlin"))) throw new Error("Gradle project state is worker-owned and cannot be declared as a generated output.");
22
+ for (const output of outputs) if (outputs.some((other) => other !== output && output.startsWith(`${other}/`))) throw new Error(`Generated output ${output} is nested inside another output declaration.`);
23
+ return {
24
+ complete: true,
25
+ ignored,
26
+ outputs
27
+ };
28
+ }
29
+ const below = (path, directory) => path === directory || path.startsWith(`${directory}/`);
30
+ function gradleStateDirectories(project) {
31
+ return [".gradle", ".kotlin"].map((name) => project ? `${project}/${name}` : name);
32
+ }
33
+ async function statIfPresent(path) {
34
+ try {
35
+ return await lstat(path);
36
+ } catch (error) {
37
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
38
+ throw error;
39
+ }
40
+ }
41
+ async function requireRealParents(repository, path, signal) {
42
+ const parts = path.split("/");
43
+ for (let index = 1; index < parts.length; index++) {
44
+ signal?.throwIfAborted();
45
+ const stat = await statIfPresent(join(repository, ...parts.slice(0, index)));
46
+ if (stat && !stat.isDirectory()) throw new Error(`Native input ${path} has a non-directory parent.`);
47
+ }
48
+ }
49
+ async function nativeGradleTransfer(root, value, signal) {
50
+ return nativeGradleInventory(root, value, [], signal, true);
51
+ }
52
+ async function nativeGradleLocalSourceDigest(root, value, localFiles, signal) {
53
+ const { project, digest } = await nativeGradleInventory(root, value, localFiles, signal, false);
54
+ return createHash("sha256").update(JSON.stringify({
55
+ project,
56
+ digest
57
+ })).digest("hex");
58
+ }
59
+ async function nativeGradleInventory(root, value, localFiles, signal, transfer) {
60
+ signal?.throwIfAborted();
61
+ const declaration = gradleOffloadInputs(value);
62
+ const repository = await realpath(await gitAsync(root, ["rev-parse", "--show-toplevel"], { signal }));
63
+ const realRoot = await realpath(root);
64
+ const project = relative(repository, realRoot).split(sep).join("/");
65
+ const local = localFiles.map((path) => resolve(realRoot, relative(root, path)));
66
+ if (project && !containedPath(project)) throw new Error("The native Gradle project leaves its repository.");
67
+ if (transfer && (await statIfPresent(join(repository, project, "buildSrc")))?.isDirectory()) throw new Error("Native Gradle offload does not support buildSrc: AGP does not report its build directories, so the worker cannot keep them.");
68
+ const state = gradleStateDirectories(project);
69
+ const files = new Map((await sourceManifest(repository, true, signal)).map((file) => [file.path, file]));
70
+ for (const path of declaration.ignored) {
71
+ await requireRealParents(repository, path, signal);
72
+ const absolute = join(repository, path);
73
+ const stat = await lstat(absolute);
74
+ if (!stat.isFile() && !stat.isSymbolicLink()) throw new Error(`Ignored native input ${path} must be an exact file or link, not a directory.`);
75
+ if (stat.isSymbolicLink()) {
76
+ const content = Buffer.from(await readlink(absolute));
77
+ files.set(path, {
78
+ path,
79
+ kind: "link",
80
+ size: content.length,
81
+ sha256: createHash("sha256").update(content).digest("hex")
82
+ });
83
+ } else files.set(path, {
84
+ path,
85
+ kind: stat.mode & 73 ? "exec" : "file",
86
+ ...await nativeFileDigest(absolute, signal)
87
+ });
88
+ }
89
+ for (const file of files.values()) {
90
+ if (local.includes(resolve(repository, file.path))) {
91
+ files.delete(file.path);
92
+ continue;
93
+ }
94
+ if (!containedPath(file.path)) throw new Error(`Native input ${file.path} is not a contained relative path.`);
95
+ await requireRealParents(repository, file.path, signal);
96
+ if (state.some((path) => below(file.path, path))) throw new Error("Gradle project state cannot be transferred as source.");
97
+ if (declaration.outputs.some((output) => below(file.path, output) || below(output, file.path))) throw new Error(`Native input ${file.path} overlaps a declared generated output.`);
98
+ if (file.path.split("/").at(-1) === "local.properties") {
99
+ if (file.kind === "link") throw new Error(`Native input ${file.path} is a machine-local properties link.`);
100
+ if ((await readFile(join(repository, file.path), {
101
+ encoding: "utf8",
102
+ signal
103
+ })).split(/\r?\n/).some((line) => line.trim() && !/^\s*[#!]/.test(line) && !/^\s*sdk\.dir\s*[:=].*[^\\]$/.test(line))) throw new Error(`Native input ${file.path} contains unsupported machine-local properties.`);
104
+ files.delete(file.path);
105
+ continue;
106
+ }
107
+ }
108
+ for (const file of files.values()) if (file.kind === "link") {
109
+ const absolute = join(repository, file.path);
110
+ const target = await readlink(absolute);
111
+ const resolved = await realpath(resolve(dirname(absolute), target));
112
+ const destination = relative(repository, resolved).split(sep).join("/");
113
+ if (isAbsolute(target) || !containedPath(destination) || !files.has(destination)) throw new Error(`Native input ${file.path} links to a target outside the declared source inventory.`);
114
+ }
115
+ for (const output of declaration.outputs) {
116
+ await requireRealParents(repository, output, signal);
117
+ const stat = await statIfPresent(join(repository, output));
118
+ if (stat && !stat.isDirectory()) throw new Error(`Generated output ${output} is not a real directory.`);
119
+ if (state.some((path) => below(output, path) || below(path, output))) throw new Error(`Generated output ${output} overlaps Gradle project state.`);
120
+ }
121
+ const empty = createHash("sha256").update("").digest("hex");
122
+ for (const path of files.keys()) {
123
+ const parts = path.split("/");
124
+ for (let index = 1; index < parts.length; index++) {
125
+ const directory = parts.slice(0, index).join("/");
126
+ files.set(directory, {
127
+ path: directory,
128
+ kind: "directory",
129
+ size: 0,
130
+ sha256: empty
131
+ });
132
+ }
133
+ }
134
+ const selected = [...files.values()].toSorted((a, b) => a.path.localeCompare(b.path));
135
+ return {
136
+ repository,
137
+ project,
138
+ declaration,
139
+ files: selected,
140
+ digest: manifestDigest(selected)
141
+ };
142
+ }
143
+ async function canonicalParent(path) {
144
+ const missing = [];
145
+ while (!await access(path).then(() => true, () => false) && dirname(path) !== path) {
146
+ missing.unshift(basename(path));
147
+ path = dirname(path);
148
+ }
149
+ return join(await realpath(path), ...missing);
150
+ }
151
+ async function nativeGradleOutputs(repository, declaration, reported, signal) {
152
+ signal?.throwIfAborted();
153
+ if (!Array.isArray(reported) || !reported.every((path) => typeof path === "string" && isAbsolute(path))) throw new Error("AGP did not report the configured native Gradle build directories.");
154
+ const real = await realpath(repository);
155
+ const reportedPaths = /* @__PURE__ */ new Set();
156
+ for (const absolute of reported) {
157
+ const resolved = resolve(absolute);
158
+ const canonical = join(await canonicalParent(dirname(resolved)), basename(resolved));
159
+ const path = relative(real, canonical).split(sep).join("/");
160
+ if (!containedPath(path)) throw new Error("A Gradle build directory leaves the transferred repository.");
161
+ await requireRealParents(repository, path, signal);
162
+ const stat = await statIfPresent(join(repository, path));
163
+ if (stat && !stat.isDirectory()) throw new Error(`Gradle build directory ${path} is not a real directory.`);
164
+ reportedPaths.add(path);
165
+ }
166
+ for (const output of declaration.outputs) if (!reportedPaths.has(output)) throw new Error(`Declared output ${output} was not reported by AGP.`);
167
+ for (const path of reportedPaths) if ((await statIfPresent(join(repository, path)))?.isDirectory() && !declaration.outputs.some((output) => below(path, output))) throw new Error(`Gradle build directory ${path} is not declared; add it to android.offloadInputs.outputs.`);
168
+ const outputs = [];
169
+ for (const path of declaration.outputs) {
170
+ signal?.throwIfAborted();
171
+ if ((await statIfPresent(join(repository, path)))?.isDirectory()) outputs.push(path);
172
+ }
173
+ return outputs;
174
+ }
175
+ function validateGradleManifest(project, declaration, files) {
176
+ gradleOffloadInputs(declaration);
177
+ if (project && !containedPath(project)) throw new Error("The native Gradle project leaves its repository.");
178
+ const excluded = [...declaration.outputs, ...gradleStateDirectories(project)];
179
+ for (const file of files) if (!containedPath(file.path) || excluded.some((path) => below(file.path, path) || file.kind !== "directory" && below(path, file.path))) throw new Error(`Native source ${file.path} overlaps worker outputs or leaves the repository.`);
180
+ for (const path of declaration.ignored) if (!files.some((file) => file.path === path && file.kind !== "directory")) throw new Error(`Declared ignored input ${path} is missing from the transfer.`);
181
+ }
182
+ async function verifyGradleTransfer(repository, project, declaration, files, digest, signal) {
183
+ signal?.throwIfAborted();
184
+ validateGradleManifest(project, declaration, files);
185
+ const excluded = [...declaration.outputs, ...gradleStateDirectories(project)];
186
+ for (const path of excluded) {
187
+ await requireRealParents(repository, path, signal);
188
+ const stat = await statIfPresent(join(repository, path));
189
+ if (stat && !stat.isDirectory()) throw new Error(`Worker output ${path} is not a real directory.`);
190
+ }
191
+ const markers = excluded.flatMap((path) => path.split("/").slice(0, -1).map((_, index) => join(repository, ...path.split("/").slice(0, index + 1))));
192
+ const snapshot = await fingerprintNativeInputs([{
193
+ name: "repository",
194
+ path: repository
195
+ }], {
196
+ excluded: [join(repository, ".git"), ...excluded.map((path) => join(repository, path))],
197
+ ignoredDirectoryMarkers: markers.filter((path) => !files.some((file) => join(repository, file.path) === path)),
198
+ parameters: null,
199
+ signal
200
+ });
201
+ const known = new Set(files.map((file) => file.path));
202
+ for (const entry of snapshot.entries) {
203
+ if (!entry.path.startsWith("repository/") || entry.path.includes("/@target")) continue;
204
+ const parts = entry.path.slice(11).split("/");
205
+ const index = parts.findIndex((_, depth) => !known.has(parts.slice(0, depth + 1).join("/")));
206
+ if (index >= 0 && (index < parts.length - 1 || entry.kind === "directory")) throw new Error(`Native Gradle directory ${parts.slice(0, index + 1).join("/")} is outside the source transfer and not a declared output reported by AGP; such directories, for example, included builds or externalNativeBuild staging, are not supported for remote builds.`);
207
+ }
208
+ return manifestDigest(await nativeTransferManifest(repository, snapshot, files, signal)) === digest;
209
+ }
210
+ //#endregion
211
+ export { nativeGradleTransfer as a, nativeGradleOutputs as i, gradleStateDirectories as n, validateGradleManifest as o, nativeGradleLocalSourceDigest as r, verifyGradleTransfer as s, gradleOffloadInputs as t };
@@ -0,0 +1,91 @@
1
+ import { createHash } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ import { dirname, join, resolve, sep } from "node:path";
4
+ import { lstat, readdir, readlink, realpath } from "node:fs/promises";
5
+ //#region src/offload/manifest.ts
6
+ function manifestDigest(entries) {
7
+ const hash = createHash("sha256");
8
+ for (const entry of entries.toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)) hash.update(`${entry.path}\0${entry.kind}\0${entry.sha256}\n`);
9
+ return hash.digest("hex");
10
+ }
11
+ //#endregion
12
+ //#region src/integrations/native-inputs.ts
13
+ var NativeInputError = class extends Error {};
14
+ async function fingerprintNativeInputs(inputs, { excluded = [], ignoredDirectoryMarkers = [], parameters, signal }) {
15
+ const exclusions = excluded.map((path) => resolve(path));
16
+ const directoryMarkers = new Set(ignoredDirectoryMarkers.map((path) => resolve(path)));
17
+ const entries = [];
18
+ const names = /* @__PURE__ */ new Set();
19
+ const isExcluded = (path) => exclusions.some((output) => path === output || path.startsWith(`${output}${sep}`));
20
+ let admit;
21
+ const record = (path, kind, content = "") => {
22
+ entries.push({
23
+ path,
24
+ kind,
25
+ sha256: createHash("sha256").update(content).digest("hex")
26
+ });
27
+ };
28
+ const walk = async (absolute, logical, ancestors, optional = false, relative = null) => {
29
+ signal?.throwIfAborted();
30
+ let stat;
31
+ try {
32
+ stat = await lstat(absolute);
33
+ } catch (error) {
34
+ if (optional && error.code === "ENOENT") {
35
+ record(logical, "absent");
36
+ return;
37
+ }
38
+ throw error;
39
+ }
40
+ if (stat.isSymbolicLink()) {
41
+ const target = await readlink(absolute);
42
+ const resolved = resolve(dirname(absolute), target);
43
+ if (isExcluded(resolved)) throw new NativeInputError(`Native input ${logical} links into an excluded output.`);
44
+ if (ancestors.has(absolute)) throw new NativeInputError(`Native input ${logical} contains a link cycle.`);
45
+ record(logical, "link", target);
46
+ await walk(resolved, `${logical}/@target`, /* @__PURE__ */ new Set([...ancestors, absolute]));
47
+ } else if (stat.isDirectory()) {
48
+ const canonical = await realpath(absolute);
49
+ if (ancestors.has(canonical)) throw new NativeInputError(`Native input ${logical} contains a directory cycle.`);
50
+ if (!directoryMarkers.has(absolute)) record(logical, "directory");
51
+ const next = /* @__PURE__ */ new Set([...ancestors, canonical]);
52
+ for (const name of (await readdir(absolute)).toSorted()) {
53
+ const child = join(absolute, name);
54
+ const childRelative = relative === null ? null : relative ? `${relative}/${name}` : name;
55
+ if (isExcluded(child) || childRelative !== null && admit && !admit(childRelative)) continue;
56
+ await walk(child, `${logical}/${name}`, next, false, childRelative);
57
+ }
58
+ } else if (stat.isFile()) {
59
+ const digest = createHash("sha256");
60
+ for await (const chunk of createReadStream(absolute, { signal })) digest.update(chunk);
61
+ entries.push({
62
+ path: logical,
63
+ kind: `file:${stat.mode & 73}`,
64
+ sha256: digest.digest("hex")
65
+ });
66
+ } else throw new NativeInputError(`Native input ${logical} is not a file, directory or symbolic link.`);
67
+ };
68
+ try {
69
+ for (const input of inputs) {
70
+ if (!input.name || names.has(input.name)) throw new NativeInputError("Native input names must be unique.");
71
+ names.add(input.name);
72
+ const path = resolve(input.path);
73
+ if (isExcluded(path)) throw new NativeInputError(`Native input ${input.name} is also an excluded output.`);
74
+ admit = input.admit;
75
+ await walk(path, input.name, /* @__PURE__ */ new Set(), input.optional, "");
76
+ }
77
+ } catch (error) {
78
+ signal?.throwIfAborted();
79
+ if (error instanceof NativeInputError) throw error;
80
+ throw new NativeInputError(`Could not read native build inputs: ${error.message}`, { cause: error });
81
+ }
82
+ signal?.throwIfAborted();
83
+ const sorted = entries.toSorted((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
84
+ return {
85
+ hash: createHash("sha256").update("stim-native-inputs-v1\0").update(JSON.stringify(parameters)).update("\0").update(manifestDigest(sorted)).digest("hex"),
86
+ entries: sorted,
87
+ parameters
88
+ };
89
+ }
90
+ //#endregion
91
+ export { fingerprintNativeInputs as n, manifestDigest as r, NativeInputError as t };