@sitepong/fastnode 0.2.1 → 0.3.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 (126) hide show
  1. package/README.md +58 -1
  2. package/dist/actions/index.cjs +891 -72
  3. package/dist/actions/index.cjs.map +1 -1
  4. package/dist/actions/index.mjs +892 -73
  5. package/dist/actions/index.mjs.map +1 -1
  6. package/dist/apple-session-jUzBrql5.d.cts +122 -0
  7. package/dist/apple-session-jUzBrql5.d.ts +122 -0
  8. package/dist/cert/index.cjs +17868 -24
  9. package/dist/cert/index.cjs.map +1 -1
  10. package/dist/cert/index.d.cts +5 -4
  11. package/dist/cert/index.d.ts +5 -4
  12. package/dist/cert/index.mjs +17853 -7
  13. package/dist/cert/index.mjs.map +1 -1
  14. package/dist/{cert-e5GAgAPb.d.ts → cert-RvXmdMke.d.ts} +2 -2
  15. package/dist/{cert-uLLdb5a7.d.cts → cert-eOoxGMN1.d.cts} +2 -2
  16. package/dist/cli/index.cjs +1364 -78
  17. package/dist/cli/index.cjs.map +1 -1
  18. package/dist/cli/index.d.cts +3 -2
  19. package/dist/cli/index.d.ts +3 -2
  20. package/dist/cli/index.mjs +1365 -79
  21. package/dist/cli/index.mjs.map +1 -1
  22. package/dist/client/index.cjs +480 -31
  23. package/dist/client/index.cjs.map +1 -1
  24. package/dist/client/index.d.cts +3 -2
  25. package/dist/client/index.d.ts +3 -2
  26. package/dist/client/index.mjs +480 -31
  27. package/dist/client/index.mjs.map +1 -1
  28. package/dist/deliver/index.cjs +334 -13
  29. package/dist/deliver/index.cjs.map +1 -1
  30. package/dist/deliver/index.d.cts +4 -3
  31. package/dist/deliver/index.d.ts +4 -3
  32. package/dist/deliver/index.mjs +330 -15
  33. package/dist/deliver/index.mjs.map +1 -1
  34. package/dist/{enums-B609j2rb.d.cts → enums-yXNVh3UI.d.cts} +8 -1
  35. package/dist/{enums-B609j2rb.d.ts → enums-yXNVh3UI.d.ts} +8 -1
  36. package/dist/gradle/index.cjs +222 -0
  37. package/dist/gradle/index.cjs.map +1 -0
  38. package/dist/gradle/index.d.cts +1 -0
  39. package/dist/gradle/index.d.ts +1 -0
  40. package/dist/gradle/index.mjs +217 -0
  41. package/dist/gradle/index.mjs.map +1 -0
  42. package/dist/gym/index.d.cts +2 -2
  43. package/dist/gym/index.d.ts +2 -2
  44. package/dist/index-8djTPW8O.d.ts +104 -0
  45. package/dist/{index-DrUpRXRG.d.cts → index-B6-MJpO4.d.cts} +1 -1
  46. package/dist/{index-Clyf4-lu.d.cts → index-BE7bwNff.d.cts} +1 -1
  47. package/dist/index-BGhV0gS-.d.ts +65 -0
  48. package/dist/index-BaNcf7jt.d.cts +201 -0
  49. package/dist/{index-Di4Ic0EE.d.ts → index-BvyZ4uiw.d.ts} +3 -3
  50. package/dist/{index-CEldrbyz.d.ts → index-C01Rkrir.d.ts} +2 -2
  51. package/dist/{index-jeI44Q5G.d.ts → index-C9mHBJED.d.ts} +1 -1
  52. package/dist/{index-BgHagzj1.d.cts → index-CAEiXVWd.d.ts} +9 -1
  53. package/dist/index-CBf0-NUQ.d.ts +201 -0
  54. package/dist/index-CXJlvmB4.d.cts +63 -0
  55. package/dist/index-CXJlvmB4.d.ts +63 -0
  56. package/dist/{index-BNP7Bpu5.d.ts → index-D1GHEM3c.d.ts} +32 -3
  57. package/dist/index-DFstwgGK.d.cts +65 -0
  58. package/dist/{index-DrCOh0Vh.d.cts → index-DGkgRnZp.d.cts} +2 -2
  59. package/dist/{index-CtydPNxA.d.cts → index-DLJso7Vs.d.cts} +32 -3
  60. package/dist/{index-BN0iWhuw.d.cts → index-DWOLZNlz.d.cts} +2 -2
  61. package/dist/{index-BjkOUQcQ.d.cts → index-DfkIz7i0.d.cts} +18 -4
  62. package/dist/{index-EKU_G1G5.d.ts → index-DjC_gmnL.d.ts} +18 -4
  63. package/dist/index-DnHQ2uT2.d.cts +104 -0
  64. package/dist/{index-CdfgEZwh.d.cts → index-DrmS802s.d.cts} +356 -130
  65. package/dist/index-Dv-Mek07.d.cts +84 -0
  66. package/dist/index-Dv-Mek07.d.ts +84 -0
  67. package/dist/{index-DHxi-QPC.d.cts → index-icIH5e5V.d.cts} +3 -3
  68. package/dist/{index-mddpvrRX.d.ts → index-laE3_wm9.d.cts} +9 -1
  69. package/dist/{index-BwwpAlk2.d.ts → index-lsuS2R1T.d.ts} +356 -130
  70. package/dist/{index-DImN9PWc.d.ts → index-mEEB7An6.d.ts} +1 -1
  71. package/dist/{index-C2YLoFVl.d.ts → index-rTZOdMRE.d.ts} +2 -2
  72. package/dist/index.cjs +20496 -217
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.d.cts +278 -22
  75. package/dist/index.d.ts +278 -22
  76. package/dist/index.mjs +20489 -220
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/lane/index.cjs +891 -72
  79. package/dist/lane/index.cjs.map +1 -1
  80. package/dist/lane/index.mjs +892 -73
  81. package/dist/lane/index.mjs.map +1 -1
  82. package/dist/match/index.d.cts +6 -5
  83. package/dist/match/index.d.ts +6 -5
  84. package/dist/pem/index.d.cts +4 -3
  85. package/dist/pem/index.d.ts +4 -3
  86. package/dist/pilot/index.cjs +8 -4
  87. package/dist/pilot/index.cjs.map +1 -1
  88. package/dist/pilot/index.d.cts +4 -3
  89. package/dist/pilot/index.d.ts +4 -3
  90. package/dist/pilot/index.mjs +10 -6
  91. package/dist/pilot/index.mjs.map +1 -1
  92. package/dist/playstore/index.cjs +207 -0
  93. package/dist/playstore/index.cjs.map +1 -0
  94. package/dist/playstore/index.d.cts +1 -0
  95. package/dist/playstore/index.d.ts +1 -0
  96. package/dist/playstore/index.mjs +203 -0
  97. package/dist/playstore/index.mjs.map +1 -0
  98. package/dist/precheck/index.d.cts +4 -3
  99. package/dist/precheck/index.d.ts +4 -3
  100. package/dist/privacy/index.cjs +207 -0
  101. package/dist/privacy/index.cjs.map +1 -0
  102. package/dist/privacy/index.d.cts +2 -0
  103. package/dist/privacy/index.d.ts +2 -0
  104. package/dist/privacy/index.mjs +195 -0
  105. package/dist/privacy/index.mjs.map +1 -0
  106. package/dist/produce/index.cjs +38 -18
  107. package/dist/produce/index.cjs.map +1 -1
  108. package/dist/produce/index.d.cts +4 -3
  109. package/dist/produce/index.d.ts +4 -3
  110. package/dist/produce/index.mjs +38 -19
  111. package/dist/produce/index.mjs.map +1 -1
  112. package/dist/review/index.cjs +141 -0
  113. package/dist/review/index.cjs.map +1 -0
  114. package/dist/review/index.d.cts +2 -0
  115. package/dist/review/index.d.ts +2 -0
  116. package/dist/review/index.mjs +137 -0
  117. package/dist/review/index.mjs.map +1 -0
  118. package/dist/sigh/index.d.cts +4 -3
  119. package/dist/sigh/index.d.ts +4 -3
  120. package/dist/xcode/index.cjs +1 -1
  121. package/dist/xcode/index.cjs.map +1 -1
  122. package/dist/xcode/index.mjs +1 -1
  123. package/dist/xcode/index.mjs.map +1 -1
  124. package/package.json +27 -1
  125. package/dist/index-BbY_H_f6.d.ts +0 -99
  126. package/dist/index-XsMsVc3O.d.cts +0 -99
@@ -0,0 +1,222 @@
1
+ 'use strict';
2
+
3
+ var child_process = require('child_process');
4
+ var promises = require('fs/promises');
5
+ var path = require('path');
6
+
7
+ // src/gradle/index.ts
8
+ function capitalize(value) {
9
+ if (!value) return value;
10
+ return value.charAt(0).toUpperCase() + value.slice(1);
11
+ }
12
+ function runGradle(cwd, args, onOutput, signal) {
13
+ return new Promise((res, rej) => {
14
+ const proc = child_process.spawn("./gradlew", args, {
15
+ cwd,
16
+ stdio: ["ignore", "pipe", "pipe"],
17
+ detached: true
18
+ });
19
+ const chunks = [];
20
+ const killGroup = (sig) => {
21
+ if (proc.pid === void 0) return;
22
+ try {
23
+ process.kill(-proc.pid, sig);
24
+ } catch {
25
+ try {
26
+ proc.kill(sig);
27
+ } catch {
28
+ }
29
+ }
30
+ };
31
+ const onAbort = () => {
32
+ chunks.push("\n[cancel] Cancellation requested \u2014 terminating Gradle...\n");
33
+ onOutput?.("\n[cancel] Cancellation requested \u2014 terminating Gradle...\n");
34
+ killGroup("SIGTERM");
35
+ setTimeout(() => killGroup("SIGKILL"), 5e3);
36
+ };
37
+ if (signal) {
38
+ if (signal.aborted) onAbort();
39
+ else signal.addEventListener("abort", onAbort, { once: true });
40
+ }
41
+ const handleData = (data) => {
42
+ const text = data.toString("utf-8");
43
+ chunks.push(text);
44
+ if (onOutput) onOutput(text);
45
+ };
46
+ proc.stdout.on("data", handleData);
47
+ proc.stderr.on("data", handleData);
48
+ proc.on("error", (err) => {
49
+ if (signal) signal.removeEventListener("abort", onAbort);
50
+ rej(err);
51
+ });
52
+ proc.on("close", (code) => {
53
+ if (signal) signal.removeEventListener("abort", onAbort);
54
+ res({ exitCode: code ?? 1, output: chunks.join("") });
55
+ });
56
+ });
57
+ }
58
+ async function findFileWithExtension(dir, ext) {
59
+ let entries;
60
+ try {
61
+ entries = await promises.readdir(dir, { withFileTypes: true });
62
+ } catch {
63
+ return null;
64
+ }
65
+ for (const entry of entries) {
66
+ const full = path.join(dir, entry.name);
67
+ if (entry.name.endsWith(ext) && !entry.isDirectory()) {
68
+ return full;
69
+ }
70
+ if (entry.isDirectory()) {
71
+ const found = await findFileWithExtension(full, ext);
72
+ if (found) return found;
73
+ }
74
+ }
75
+ return null;
76
+ }
77
+ function stampAndroidVersion(source, versionCode, versionName) {
78
+ let codeFound = false;
79
+ let nameFound = false;
80
+ let out = source.replace(/^(\s*versionCode)(\s*=\s*|\s+)\d+/m, (_m, key, sep) => {
81
+ codeFound = true;
82
+ return `${key}${sep}${versionCode}`;
83
+ });
84
+ if (versionName) {
85
+ out = out.replace(/^(\s*versionName)(\s*=\s*|\s+)(["'])[^"'\n]*\3/m, (_m, key, sep, q) => {
86
+ nameFound = true;
87
+ return `${key}${sep}${q}${versionName}${q}`;
88
+ });
89
+ }
90
+ return { source: out, versionCode: codeFound, versionName: nameFound };
91
+ }
92
+ async function setAndroidVersion(projectDir, versionCode, versionName) {
93
+ for (const name of ["build.gradle", "build.gradle.kts"]) {
94
+ const file = path.join(projectDir, "app", name);
95
+ let source;
96
+ try {
97
+ source = await promises.readFile(file, "utf8");
98
+ } catch {
99
+ continue;
100
+ }
101
+ const result = stampAndroidVersion(source, versionCode, versionName);
102
+ if (result.source !== source) await promises.writeFile(file, result.source);
103
+ return { file, versionCode: result.versionCode, versionName: result.versionName };
104
+ }
105
+ throw new Error(`No app/build.gradle or app/build.gradle.kts under ${projectDir}`);
106
+ }
107
+ async function detectAndroidDir(rootDir) {
108
+ const root = path.resolve(rootDir);
109
+ const hasGradlew = async (dir) => {
110
+ try {
111
+ const s = await promises.stat(path.join(dir, "gradlew"));
112
+ return s.isFile();
113
+ } catch {
114
+ return false;
115
+ }
116
+ };
117
+ if (await hasGradlew(root)) return root;
118
+ const androidDir = path.join(root, "android");
119
+ if (await hasGradlew(androidDir)) return androidDir;
120
+ throw new Error(
121
+ `Could not find gradlew in ${root} or ${androidDir}. Pass the directory containing gradlew as projectDir.`
122
+ );
123
+ }
124
+ async function ensureGradleMemory(projectDir, jvmArgs) {
125
+ const file = path.join(projectDir, "gradle.properties");
126
+ let contents = "";
127
+ try {
128
+ contents = await promises.readFile(file, "utf-8");
129
+ } catch {
130
+ }
131
+ const line = `org.gradle.jvmargs=${jvmArgs}`;
132
+ const re = /^org\.gradle\.jvmargs=.*$/m;
133
+ if (re.test(contents)) {
134
+ contents = contents.replace(re, line);
135
+ } else {
136
+ contents = contents.replace(/\s*$/, "") + `
137
+ ${line}
138
+ `;
139
+ }
140
+ await promises.writeFile(file, contents, "utf-8");
141
+ }
142
+ async function buildAndroid(options) {
143
+ const projectDir = await detectAndroidDir(options.projectDir);
144
+ const buildType = options.buildType ?? "Release";
145
+ const flavorPart = options.flavor ? capitalize(options.flavor) : "";
146
+ const variant = options.flavor ? options.flavor + capitalize(buildType) : buildType.charAt(0).toLowerCase() + buildType.slice(1);
147
+ const bundleTask = `bundle${flavorPart}${capitalize(buildType)}`;
148
+ const assembleTask = `assemble${flavorPart}${capitalize(buildType)}`;
149
+ const tasks = [];
150
+ if (options.outputType === "aab" || options.outputType === "both") {
151
+ tasks.push(bundleTask);
152
+ }
153
+ if (options.outputType === "apk" || options.outputType === "both") {
154
+ tasks.push(assembleTask);
155
+ }
156
+ const signingArgs = [
157
+ `-Pandroid.injected.signing.store.file=${path.resolve(options.keystorePath)}`,
158
+ `-Pandroid.injected.signing.store.password=${options.keystorePassword}`,
159
+ `-Pandroid.injected.signing.key.alias=${options.keyAlias}`,
160
+ `-Pandroid.injected.signing.key.password=${options.keyPassword}`
161
+ ];
162
+ const args = [...tasks, "--no-daemon", ...signingArgs];
163
+ const fullOutput = [];
164
+ const onOutput = (chunk) => {
165
+ fullOutput.push(chunk);
166
+ if (options.onOutput) options.onOutput(chunk);
167
+ };
168
+ await promises.chmod(path.join(projectDir, "gradlew"), 493).catch(() => {
169
+ });
170
+ const jvmArgs = options.jvmArgs === void 0 ? "-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8" : options.jvmArgs;
171
+ if (jvmArgs) {
172
+ await ensureGradleMemory(projectDir, jvmArgs);
173
+ }
174
+ const result = await runGradle(projectDir, args, onOutput, options.signal);
175
+ if (result.exitCode !== 0) {
176
+ return {
177
+ success: false,
178
+ exitCode: result.exitCode,
179
+ logContent: fullOutput.join("")
180
+ };
181
+ }
182
+ let aabPath;
183
+ let apkPath;
184
+ if (options.outputType === "aab" || options.outputType === "both") {
185
+ const bundleDir = path.join(
186
+ projectDir,
187
+ "app",
188
+ "build",
189
+ "outputs",
190
+ "bundle",
191
+ variant
192
+ );
193
+ const found = await findFileWithExtension(bundleDir, ".aab");
194
+ if (found) aabPath = found;
195
+ }
196
+ if (options.outputType === "apk" || options.outputType === "both") {
197
+ const apkDir = path.join(
198
+ projectDir,
199
+ "app",
200
+ "build",
201
+ "outputs",
202
+ "apk",
203
+ variant
204
+ );
205
+ const found = await findFileWithExtension(apkDir, ".apk");
206
+ if (found) apkPath = found;
207
+ }
208
+ return {
209
+ success: true,
210
+ exitCode: 0,
211
+ aabPath,
212
+ apkPath,
213
+ logContent: fullOutput.join("")
214
+ };
215
+ }
216
+
217
+ exports.buildAndroid = buildAndroid;
218
+ exports.detectAndroidDir = detectAndroidDir;
219
+ exports.setAndroidVersion = setAndroidVersion;
220
+ exports.stampAndroidVersion = stampAndroidVersion;
221
+ //# sourceMappingURL=index.cjs.map
222
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/gradle/index.ts"],"names":["spawn","readdir","join","readFile","writeFile","resolve","stat","chmod"],"mappings":"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","file":"index.cjs","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { chmod, readFile, readdir, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport type AndroidOutputType = \"aab\" | \"apk\" | \"both\";\n\nexport interface GradleBuildOptions {\n /** The android/ dir or app root containing `gradlew`. */\n projectDir: string;\n /** Which artifact(s) to produce. */\n outputType: AndroidOutputType;\n /** Product flavor (e.g. \"prod\") — capitalized into the Gradle task name. */\n flavor?: string;\n /** Build type, defaults to \"Release\". */\n buildType?: string;\n /**\n * JVM args for the Gradle daemon. Defaults to a raised heap/metaspace\n * (`-Xmx3072m -XX:MaxMetaspaceSize=1024m`) because Expo's generated\n * `gradle.properties` caps metaspace at 512m, which OOMs on large RN\n * module graphs (Kotlin/AGP class metadata). Set to `null` to leave the\n * project's `gradle.properties` untouched.\n */\n jvmArgs?: string | null;\n /** Absolute (or resolvable) path to the keystore file. */\n keystorePath: string;\n keystorePassword: string;\n keyAlias: string;\n keyPassword: string;\n onOutput?: (chunk: string) => void;\n /** When aborted, the gradlew process group is killed to stop the build. */\n signal?: AbortSignal;\n}\n\nexport interface GradleBuildResult {\n success: boolean;\n exitCode: number;\n aabPath?: string;\n apkPath?: string;\n logContent: string;\n}\n\n// ── Internal helpers ───────────────────────────────────────────────────────\n\n/** Uppercase the first character (for variant/task name composition). */\nfunction capitalize(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\n/**\n * Spawn `./gradlew` with the given args, streaming stdout/stderr to the\n * optional `onOutput` callback and collecting full output.\n */\nfunction runGradle(\n cwd: string,\n args: string[],\n onOutput?: (chunk: string) => void,\n signal?: AbortSignal,\n): Promise<{ exitCode: number; output: string }> {\n return new Promise((res, rej) => {\n // detached:true makes the child a process-group leader so the whole Gradle\n // tree (daemon workers, kotlinc, etc.) can be signalled with kill(-pid).\n const proc = spawn(\"./gradlew\", args, {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n const chunks: string[] = [];\n\n const killGroup = (sig: NodeJS.Signals) => {\n if (proc.pid === undefined) return;\n try { process.kill(-proc.pid, sig); }\n catch { try { proc.kill(sig); } catch { /* already gone */ } }\n };\n const onAbort = () => {\n chunks.push(\"\\n[cancel] Cancellation requested — terminating Gradle...\\n\");\n onOutput?.(\"\\n[cancel] Cancellation requested — terminating Gradle...\\n\");\n killGroup(\"SIGTERM\");\n setTimeout(() => killGroup(\"SIGKILL\"), 5_000);\n };\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n const handleData = (data: Buffer) => {\n const text = data.toString(\"utf-8\");\n chunks.push(text);\n if (onOutput) onOutput(text);\n };\n\n proc.stdout.on(\"data\", handleData);\n proc.stderr.on(\"data\", handleData);\n proc.on(\"error\", (err) => {\n if (signal) signal.removeEventListener(\"abort\", onAbort);\n rej(err);\n });\n proc.on(\"close\", (code) => {\n if (signal) signal.removeEventListener(\"abort\", onAbort);\n res({ exitCode: code ?? 1, output: chunks.join(\"\") });\n });\n });\n}\n\n/**\n * Recursively find the first file matching `ext` inside `dir`.\n */\nasync function findFileWithExtension(\n dir: string,\n ext: string,\n): Promise<string | null> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return null;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.name.endsWith(ext) && !entry.isDirectory()) {\n return full;\n }\n if (entry.isDirectory()) {\n const found = await findFileWithExtension(full, ext);\n if (found) return found;\n }\n }\n return null;\n}\n\n/**\n * Rewrite `versionCode` (and `versionName`, when given) in an app module's\n * Gradle file, Groovy (`versionCode 1`) or Kotlin DSL (`versionCode = 1`).\n * Returns the new source and whether each value was found.\n */\nexport function stampAndroidVersion(\n source: string,\n versionCode: number,\n versionName?: string | null,\n): { source: string; versionCode: boolean; versionName: boolean } {\n let codeFound = false;\n let nameFound = false;\n let out = source.replace(/^(\\s*versionCode)(\\s*=\\s*|\\s+)\\d+/m, (_m, key: string, sep: string) => {\n codeFound = true;\n return `${key}${sep}${versionCode}`;\n });\n if (versionName) {\n out = out.replace(/^(\\s*versionName)(\\s*=\\s*|\\s+)([\"'])[^\"'\\n]*\\3/m, (_m, key: string, sep: string, q: string) => {\n nameFound = true;\n return `${key}${sep}${q}${versionName}${q}`;\n });\n }\n return { source: out, versionCode: codeFound, versionName: nameFound };\n}\n\n/**\n * Stamp the build's version into `android/app/build.gradle(.kts)`. Play refuses\n * a versionCode it has seen, so each build must carry its own.\n */\nexport async function setAndroidVersion(\n projectDir: string,\n versionCode: number,\n versionName?: string | null,\n): Promise<{ file: string; versionCode: boolean; versionName: boolean }> {\n for (const name of [\"build.gradle\", \"build.gradle.kts\"]) {\n const file = join(projectDir, \"app\", name);\n let source: string;\n try {\n source = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n const result = stampAndroidVersion(source, versionCode, versionName);\n if (result.source !== source) await writeFile(file, result.source);\n return { file, versionCode: result.versionCode, versionName: result.versionName };\n }\n throw new Error(`No app/build.gradle or app/build.gradle.kts under ${projectDir}`);\n}\n\n/**\n * Resolve the directory that contains `gradlew`. Accepts either the app root\n * (which contains an `android/` subdirectory) or the `android/` dir itself.\n */\nexport async function detectAndroidDir(rootDir: string): Promise<string> {\n const root = resolve(rootDir);\n\n const hasGradlew = async (dir: string): Promise<boolean> => {\n try {\n const s = await stat(join(dir, \"gradlew\"));\n return s.isFile();\n } catch {\n return false;\n }\n };\n\n if (await hasGradlew(root)) return root;\n\n const androidDir = join(root, \"android\");\n if (await hasGradlew(androidDir)) return androidDir;\n\n throw new Error(\n `Could not find gradlew in ${root} or ${androidDir}. ` +\n `Pass the directory containing gradlew as projectDir.`,\n );\n}\n\n/**\n * Ensure `android/gradle.properties` grants the Gradle daemon enough heap and\n * metaspace. Expo's template sets `org.gradle.jvmargs=-Xmx2048m\n * -XX:MaxMetaspaceSize=512m`, which OOMs (\"Metaspace\") on large RN apps. We\n * replace (or append) the line with the requested args. Idempotent.\n */\nasync function ensureGradleMemory(\n projectDir: string,\n jvmArgs: string,\n): Promise<void> {\n const file = join(projectDir, \"gradle.properties\");\n let contents = \"\";\n try {\n contents = await readFile(file, \"utf-8\");\n } catch {\n // No gradle.properties — create one with just the jvmargs line.\n }\n const line = `org.gradle.jvmargs=${jvmArgs}`;\n const re = /^org\\.gradle\\.jvmargs=.*$/m;\n if (re.test(contents)) {\n contents = contents.replace(re, line);\n } else {\n contents = contents.replace(/\\s*$/, \"\") + `\\n${line}\\n`;\n }\n await writeFile(file, contents, \"utf-8\");\n}\n\n// ── Main entry point ─────────────────────────────────────────────────────────\n\n/**\n * Build an Android app using Gradle (`./gradlew`).\n * This is the Android-side equivalent of `gym` (iOS).\n *\n * Steps:\n * 1. Resolve the gradlew directory.\n * 2. chmod +x gradlew so it's executable on fresh checkouts.\n * 3. Run the appropriate task(s) (bundle/assemble), injecting the signing\n * config via standard AGP `-Pandroid.injected.signing.*` properties.\n * 4. Locate produced AAB/APK artifacts by globbing standard output paths.\n * 5. Return a GradleBuildResult.\n */\nexport async function buildAndroid(\n options: GradleBuildOptions,\n): Promise<GradleBuildResult> {\n const projectDir = await detectAndroidDir(options.projectDir);\n\n const buildType = options.buildType ?? \"Release\";\n const flavorPart = options.flavor ? capitalize(options.flavor) : \"\";\n // Variant directory name used in build/outputs, e.g. \"prodRelease\" or \"release\".\n const variant = options.flavor\n ? options.flavor + capitalize(buildType)\n : buildType.charAt(0).toLowerCase() + buildType.slice(1);\n\n // Compose the gradle task names, e.g. \"bundleProdRelease\" / \"assembleRelease\".\n const bundleTask = `bundle${flavorPart}${capitalize(buildType)}`;\n const assembleTask = `assemble${flavorPart}${capitalize(buildType)}`;\n\n const tasks: string[] = [];\n if (options.outputType === \"aab\" || options.outputType === \"both\") {\n tasks.push(bundleTask);\n }\n if (options.outputType === \"apk\" || options.outputType === \"both\") {\n tasks.push(assembleTask);\n }\n\n // Standard AGP injected signing properties — understood by AGP/Gradle for\n // any signing-aware build task without editing build.gradle.\n const signingArgs = [\n `-Pandroid.injected.signing.store.file=${resolve(options.keystorePath)}`,\n `-Pandroid.injected.signing.store.password=${options.keystorePassword}`,\n `-Pandroid.injected.signing.key.alias=${options.keyAlias}`,\n `-Pandroid.injected.signing.key.password=${options.keyPassword}`,\n ];\n\n // `--no-daemon`: build runners are ephemeral and re-run back-to-back. A\n // persistent Gradle daemon (with our raised heap) survives between builds and\n // stacks up, exhausting RAM on small runners. No-daemon keeps each build to a\n // single short-lived JVM.\n const args = [...tasks, \"--no-daemon\", ...signingArgs];\n\n const fullOutput: string[] = [];\n const onOutput = (chunk: string) => {\n fullOutput.push(chunk);\n if (options.onOutput) options.onOutput(chunk);\n };\n\n // Make gradlew executable (fresh checkouts may lack the +x bit).\n await chmod(join(projectDir, \"gradlew\"), 0o755).catch(() => {});\n\n // Raise the daemon's heap/metaspace unless the caller opted out (null).\n const jvmArgs =\n options.jvmArgs === undefined\n ? \"-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8\"\n : options.jvmArgs;\n if (jvmArgs) {\n await ensureGradleMemory(projectDir, jvmArgs);\n }\n\n const result = await runGradle(projectDir, args, onOutput, options.signal);\n\n if (result.exitCode !== 0) {\n return {\n success: false,\n exitCode: result.exitCode,\n logContent: fullOutput.join(\"\"),\n };\n }\n\n // ── Locate artifacts ──────────────────────────────────────────────────\n\n let aabPath: string | undefined;\n let apkPath: string | undefined;\n\n if (options.outputType === \"aab\" || options.outputType === \"both\") {\n const bundleDir = join(\n projectDir,\n \"app\",\n \"build\",\n \"outputs\",\n \"bundle\",\n variant,\n );\n const found = await findFileWithExtension(bundleDir, \".aab\");\n if (found) aabPath = found;\n }\n\n if (options.outputType === \"apk\" || options.outputType === \"both\") {\n const apkDir = join(\n projectDir,\n \"app\",\n \"build\",\n \"outputs\",\n \"apk\",\n variant,\n );\n const found = await findFileWithExtension(apkDir, \".apk\");\n if (found) apkPath = found;\n }\n\n return {\n success: true,\n exitCode: 0,\n aabPath,\n apkPath,\n logContent: fullOutput.join(\"\"),\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export { A as AndroidOutputType, G as GradleBuildOptions, a as GradleBuildResult, c as buildAndroid, d as detectAndroidDir, b as setAndroidVersion, s as stampAndroidVersion } from '../index-Dv-Mek07.cjs';
@@ -0,0 +1 @@
1
+ export { A as AndroidOutputType, G as GradleBuildOptions, a as GradleBuildResult, c as buildAndroid, d as detectAndroidDir, b as setAndroidVersion, s as stampAndroidVersion } from '../index-Dv-Mek07.js';
@@ -0,0 +1,217 @@
1
+ import { spawn } from 'child_process';
2
+ import { readFile, writeFile, chmod, stat, readdir } from 'fs/promises';
3
+ import { join, resolve } from 'path';
4
+
5
+ // src/gradle/index.ts
6
+ function capitalize(value) {
7
+ if (!value) return value;
8
+ return value.charAt(0).toUpperCase() + value.slice(1);
9
+ }
10
+ function runGradle(cwd, args, onOutput, signal) {
11
+ return new Promise((res, rej) => {
12
+ const proc = spawn("./gradlew", args, {
13
+ cwd,
14
+ stdio: ["ignore", "pipe", "pipe"],
15
+ detached: true
16
+ });
17
+ const chunks = [];
18
+ const killGroup = (sig) => {
19
+ if (proc.pid === void 0) return;
20
+ try {
21
+ process.kill(-proc.pid, sig);
22
+ } catch {
23
+ try {
24
+ proc.kill(sig);
25
+ } catch {
26
+ }
27
+ }
28
+ };
29
+ const onAbort = () => {
30
+ chunks.push("\n[cancel] Cancellation requested \u2014 terminating Gradle...\n");
31
+ onOutput?.("\n[cancel] Cancellation requested \u2014 terminating Gradle...\n");
32
+ killGroup("SIGTERM");
33
+ setTimeout(() => killGroup("SIGKILL"), 5e3);
34
+ };
35
+ if (signal) {
36
+ if (signal.aborted) onAbort();
37
+ else signal.addEventListener("abort", onAbort, { once: true });
38
+ }
39
+ const handleData = (data) => {
40
+ const text = data.toString("utf-8");
41
+ chunks.push(text);
42
+ if (onOutput) onOutput(text);
43
+ };
44
+ proc.stdout.on("data", handleData);
45
+ proc.stderr.on("data", handleData);
46
+ proc.on("error", (err) => {
47
+ if (signal) signal.removeEventListener("abort", onAbort);
48
+ rej(err);
49
+ });
50
+ proc.on("close", (code) => {
51
+ if (signal) signal.removeEventListener("abort", onAbort);
52
+ res({ exitCode: code ?? 1, output: chunks.join("") });
53
+ });
54
+ });
55
+ }
56
+ async function findFileWithExtension(dir, ext) {
57
+ let entries;
58
+ try {
59
+ entries = await readdir(dir, { withFileTypes: true });
60
+ } catch {
61
+ return null;
62
+ }
63
+ for (const entry of entries) {
64
+ const full = join(dir, entry.name);
65
+ if (entry.name.endsWith(ext) && !entry.isDirectory()) {
66
+ return full;
67
+ }
68
+ if (entry.isDirectory()) {
69
+ const found = await findFileWithExtension(full, ext);
70
+ if (found) return found;
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ function stampAndroidVersion(source, versionCode, versionName) {
76
+ let codeFound = false;
77
+ let nameFound = false;
78
+ let out = source.replace(/^(\s*versionCode)(\s*=\s*|\s+)\d+/m, (_m, key, sep) => {
79
+ codeFound = true;
80
+ return `${key}${sep}${versionCode}`;
81
+ });
82
+ if (versionName) {
83
+ out = out.replace(/^(\s*versionName)(\s*=\s*|\s+)(["'])[^"'\n]*\3/m, (_m, key, sep, q) => {
84
+ nameFound = true;
85
+ return `${key}${sep}${q}${versionName}${q}`;
86
+ });
87
+ }
88
+ return { source: out, versionCode: codeFound, versionName: nameFound };
89
+ }
90
+ async function setAndroidVersion(projectDir, versionCode, versionName) {
91
+ for (const name of ["build.gradle", "build.gradle.kts"]) {
92
+ const file = join(projectDir, "app", name);
93
+ let source;
94
+ try {
95
+ source = await readFile(file, "utf8");
96
+ } catch {
97
+ continue;
98
+ }
99
+ const result = stampAndroidVersion(source, versionCode, versionName);
100
+ if (result.source !== source) await writeFile(file, result.source);
101
+ return { file, versionCode: result.versionCode, versionName: result.versionName };
102
+ }
103
+ throw new Error(`No app/build.gradle or app/build.gradle.kts under ${projectDir}`);
104
+ }
105
+ async function detectAndroidDir(rootDir) {
106
+ const root = resolve(rootDir);
107
+ const hasGradlew = async (dir) => {
108
+ try {
109
+ const s = await stat(join(dir, "gradlew"));
110
+ return s.isFile();
111
+ } catch {
112
+ return false;
113
+ }
114
+ };
115
+ if (await hasGradlew(root)) return root;
116
+ const androidDir = join(root, "android");
117
+ if (await hasGradlew(androidDir)) return androidDir;
118
+ throw new Error(
119
+ `Could not find gradlew in ${root} or ${androidDir}. Pass the directory containing gradlew as projectDir.`
120
+ );
121
+ }
122
+ async function ensureGradleMemory(projectDir, jvmArgs) {
123
+ const file = join(projectDir, "gradle.properties");
124
+ let contents = "";
125
+ try {
126
+ contents = await readFile(file, "utf-8");
127
+ } catch {
128
+ }
129
+ const line = `org.gradle.jvmargs=${jvmArgs}`;
130
+ const re = /^org\.gradle\.jvmargs=.*$/m;
131
+ if (re.test(contents)) {
132
+ contents = contents.replace(re, line);
133
+ } else {
134
+ contents = contents.replace(/\s*$/, "") + `
135
+ ${line}
136
+ `;
137
+ }
138
+ await writeFile(file, contents, "utf-8");
139
+ }
140
+ async function buildAndroid(options) {
141
+ const projectDir = await detectAndroidDir(options.projectDir);
142
+ const buildType = options.buildType ?? "Release";
143
+ const flavorPart = options.flavor ? capitalize(options.flavor) : "";
144
+ const variant = options.flavor ? options.flavor + capitalize(buildType) : buildType.charAt(0).toLowerCase() + buildType.slice(1);
145
+ const bundleTask = `bundle${flavorPart}${capitalize(buildType)}`;
146
+ const assembleTask = `assemble${flavorPart}${capitalize(buildType)}`;
147
+ const tasks = [];
148
+ if (options.outputType === "aab" || options.outputType === "both") {
149
+ tasks.push(bundleTask);
150
+ }
151
+ if (options.outputType === "apk" || options.outputType === "both") {
152
+ tasks.push(assembleTask);
153
+ }
154
+ const signingArgs = [
155
+ `-Pandroid.injected.signing.store.file=${resolve(options.keystorePath)}`,
156
+ `-Pandroid.injected.signing.store.password=${options.keystorePassword}`,
157
+ `-Pandroid.injected.signing.key.alias=${options.keyAlias}`,
158
+ `-Pandroid.injected.signing.key.password=${options.keyPassword}`
159
+ ];
160
+ const args = [...tasks, "--no-daemon", ...signingArgs];
161
+ const fullOutput = [];
162
+ const onOutput = (chunk) => {
163
+ fullOutput.push(chunk);
164
+ if (options.onOutput) options.onOutput(chunk);
165
+ };
166
+ await chmod(join(projectDir, "gradlew"), 493).catch(() => {
167
+ });
168
+ const jvmArgs = options.jvmArgs === void 0 ? "-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8" : options.jvmArgs;
169
+ if (jvmArgs) {
170
+ await ensureGradleMemory(projectDir, jvmArgs);
171
+ }
172
+ const result = await runGradle(projectDir, args, onOutput, options.signal);
173
+ if (result.exitCode !== 0) {
174
+ return {
175
+ success: false,
176
+ exitCode: result.exitCode,
177
+ logContent: fullOutput.join("")
178
+ };
179
+ }
180
+ let aabPath;
181
+ let apkPath;
182
+ if (options.outputType === "aab" || options.outputType === "both") {
183
+ const bundleDir = join(
184
+ projectDir,
185
+ "app",
186
+ "build",
187
+ "outputs",
188
+ "bundle",
189
+ variant
190
+ );
191
+ const found = await findFileWithExtension(bundleDir, ".aab");
192
+ if (found) aabPath = found;
193
+ }
194
+ if (options.outputType === "apk" || options.outputType === "both") {
195
+ const apkDir = join(
196
+ projectDir,
197
+ "app",
198
+ "build",
199
+ "outputs",
200
+ "apk",
201
+ variant
202
+ );
203
+ const found = await findFileWithExtension(apkDir, ".apk");
204
+ if (found) apkPath = found;
205
+ }
206
+ return {
207
+ success: true,
208
+ exitCode: 0,
209
+ aabPath,
210
+ apkPath,
211
+ logContent: fullOutput.join("")
212
+ };
213
+ }
214
+
215
+ export { buildAndroid, detectAndroidDir, setAndroidVersion, stampAndroidVersion };
216
+ //# sourceMappingURL=index.mjs.map
217
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/gradle/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { chmod, readFile, readdir, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport type AndroidOutputType = \"aab\" | \"apk\" | \"both\";\n\nexport interface GradleBuildOptions {\n /** The android/ dir or app root containing `gradlew`. */\n projectDir: string;\n /** Which artifact(s) to produce. */\n outputType: AndroidOutputType;\n /** Product flavor (e.g. \"prod\") — capitalized into the Gradle task name. */\n flavor?: string;\n /** Build type, defaults to \"Release\". */\n buildType?: string;\n /**\n * JVM args for the Gradle daemon. Defaults to a raised heap/metaspace\n * (`-Xmx3072m -XX:MaxMetaspaceSize=1024m`) because Expo's generated\n * `gradle.properties` caps metaspace at 512m, which OOMs on large RN\n * module graphs (Kotlin/AGP class metadata). Set to `null` to leave the\n * project's `gradle.properties` untouched.\n */\n jvmArgs?: string | null;\n /** Absolute (or resolvable) path to the keystore file. */\n keystorePath: string;\n keystorePassword: string;\n keyAlias: string;\n keyPassword: string;\n onOutput?: (chunk: string) => void;\n /** When aborted, the gradlew process group is killed to stop the build. */\n signal?: AbortSignal;\n}\n\nexport interface GradleBuildResult {\n success: boolean;\n exitCode: number;\n aabPath?: string;\n apkPath?: string;\n logContent: string;\n}\n\n// ── Internal helpers ───────────────────────────────────────────────────────\n\n/** Uppercase the first character (for variant/task name composition). */\nfunction capitalize(value: string): string {\n if (!value) return value;\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n\n/**\n * Spawn `./gradlew` with the given args, streaming stdout/stderr to the\n * optional `onOutput` callback and collecting full output.\n */\nfunction runGradle(\n cwd: string,\n args: string[],\n onOutput?: (chunk: string) => void,\n signal?: AbortSignal,\n): Promise<{ exitCode: number; output: string }> {\n return new Promise((res, rej) => {\n // detached:true makes the child a process-group leader so the whole Gradle\n // tree (daemon workers, kotlinc, etc.) can be signalled with kill(-pid).\n const proc = spawn(\"./gradlew\", args, {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n\n const chunks: string[] = [];\n\n const killGroup = (sig: NodeJS.Signals) => {\n if (proc.pid === undefined) return;\n try { process.kill(-proc.pid, sig); }\n catch { try { proc.kill(sig); } catch { /* already gone */ } }\n };\n const onAbort = () => {\n chunks.push(\"\\n[cancel] Cancellation requested — terminating Gradle...\\n\");\n onOutput?.(\"\\n[cancel] Cancellation requested — terminating Gradle...\\n\");\n killGroup(\"SIGTERM\");\n setTimeout(() => killGroup(\"SIGKILL\"), 5_000);\n };\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n\n const handleData = (data: Buffer) => {\n const text = data.toString(\"utf-8\");\n chunks.push(text);\n if (onOutput) onOutput(text);\n };\n\n proc.stdout.on(\"data\", handleData);\n proc.stderr.on(\"data\", handleData);\n proc.on(\"error\", (err) => {\n if (signal) signal.removeEventListener(\"abort\", onAbort);\n rej(err);\n });\n proc.on(\"close\", (code) => {\n if (signal) signal.removeEventListener(\"abort\", onAbort);\n res({ exitCode: code ?? 1, output: chunks.join(\"\") });\n });\n });\n}\n\n/**\n * Recursively find the first file matching `ext` inside `dir`.\n */\nasync function findFileWithExtension(\n dir: string,\n ext: string,\n): Promise<string | null> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return null;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.name.endsWith(ext) && !entry.isDirectory()) {\n return full;\n }\n if (entry.isDirectory()) {\n const found = await findFileWithExtension(full, ext);\n if (found) return found;\n }\n }\n return null;\n}\n\n/**\n * Rewrite `versionCode` (and `versionName`, when given) in an app module's\n * Gradle file, Groovy (`versionCode 1`) or Kotlin DSL (`versionCode = 1`).\n * Returns the new source and whether each value was found.\n */\nexport function stampAndroidVersion(\n source: string,\n versionCode: number,\n versionName?: string | null,\n): { source: string; versionCode: boolean; versionName: boolean } {\n let codeFound = false;\n let nameFound = false;\n let out = source.replace(/^(\\s*versionCode)(\\s*=\\s*|\\s+)\\d+/m, (_m, key: string, sep: string) => {\n codeFound = true;\n return `${key}${sep}${versionCode}`;\n });\n if (versionName) {\n out = out.replace(/^(\\s*versionName)(\\s*=\\s*|\\s+)([\"'])[^\"'\\n]*\\3/m, (_m, key: string, sep: string, q: string) => {\n nameFound = true;\n return `${key}${sep}${q}${versionName}${q}`;\n });\n }\n return { source: out, versionCode: codeFound, versionName: nameFound };\n}\n\n/**\n * Stamp the build's version into `android/app/build.gradle(.kts)`. Play refuses\n * a versionCode it has seen, so each build must carry its own.\n */\nexport async function setAndroidVersion(\n projectDir: string,\n versionCode: number,\n versionName?: string | null,\n): Promise<{ file: string; versionCode: boolean; versionName: boolean }> {\n for (const name of [\"build.gradle\", \"build.gradle.kts\"]) {\n const file = join(projectDir, \"app\", name);\n let source: string;\n try {\n source = await readFile(file, \"utf8\");\n } catch {\n continue;\n }\n const result = stampAndroidVersion(source, versionCode, versionName);\n if (result.source !== source) await writeFile(file, result.source);\n return { file, versionCode: result.versionCode, versionName: result.versionName };\n }\n throw new Error(`No app/build.gradle or app/build.gradle.kts under ${projectDir}`);\n}\n\n/**\n * Resolve the directory that contains `gradlew`. Accepts either the app root\n * (which contains an `android/` subdirectory) or the `android/` dir itself.\n */\nexport async function detectAndroidDir(rootDir: string): Promise<string> {\n const root = resolve(rootDir);\n\n const hasGradlew = async (dir: string): Promise<boolean> => {\n try {\n const s = await stat(join(dir, \"gradlew\"));\n return s.isFile();\n } catch {\n return false;\n }\n };\n\n if (await hasGradlew(root)) return root;\n\n const androidDir = join(root, \"android\");\n if (await hasGradlew(androidDir)) return androidDir;\n\n throw new Error(\n `Could not find gradlew in ${root} or ${androidDir}. ` +\n `Pass the directory containing gradlew as projectDir.`,\n );\n}\n\n/**\n * Ensure `android/gradle.properties` grants the Gradle daemon enough heap and\n * metaspace. Expo's template sets `org.gradle.jvmargs=-Xmx2048m\n * -XX:MaxMetaspaceSize=512m`, which OOMs (\"Metaspace\") on large RN apps. We\n * replace (or append) the line with the requested args. Idempotent.\n */\nasync function ensureGradleMemory(\n projectDir: string,\n jvmArgs: string,\n): Promise<void> {\n const file = join(projectDir, \"gradle.properties\");\n let contents = \"\";\n try {\n contents = await readFile(file, \"utf-8\");\n } catch {\n // No gradle.properties — create one with just the jvmargs line.\n }\n const line = `org.gradle.jvmargs=${jvmArgs}`;\n const re = /^org\\.gradle\\.jvmargs=.*$/m;\n if (re.test(contents)) {\n contents = contents.replace(re, line);\n } else {\n contents = contents.replace(/\\s*$/, \"\") + `\\n${line}\\n`;\n }\n await writeFile(file, contents, \"utf-8\");\n}\n\n// ── Main entry point ─────────────────────────────────────────────────────────\n\n/**\n * Build an Android app using Gradle (`./gradlew`).\n * This is the Android-side equivalent of `gym` (iOS).\n *\n * Steps:\n * 1. Resolve the gradlew directory.\n * 2. chmod +x gradlew so it's executable on fresh checkouts.\n * 3. Run the appropriate task(s) (bundle/assemble), injecting the signing\n * config via standard AGP `-Pandroid.injected.signing.*` properties.\n * 4. Locate produced AAB/APK artifacts by globbing standard output paths.\n * 5. Return a GradleBuildResult.\n */\nexport async function buildAndroid(\n options: GradleBuildOptions,\n): Promise<GradleBuildResult> {\n const projectDir = await detectAndroidDir(options.projectDir);\n\n const buildType = options.buildType ?? \"Release\";\n const flavorPart = options.flavor ? capitalize(options.flavor) : \"\";\n // Variant directory name used in build/outputs, e.g. \"prodRelease\" or \"release\".\n const variant = options.flavor\n ? options.flavor + capitalize(buildType)\n : buildType.charAt(0).toLowerCase() + buildType.slice(1);\n\n // Compose the gradle task names, e.g. \"bundleProdRelease\" / \"assembleRelease\".\n const bundleTask = `bundle${flavorPart}${capitalize(buildType)}`;\n const assembleTask = `assemble${flavorPart}${capitalize(buildType)}`;\n\n const tasks: string[] = [];\n if (options.outputType === \"aab\" || options.outputType === \"both\") {\n tasks.push(bundleTask);\n }\n if (options.outputType === \"apk\" || options.outputType === \"both\") {\n tasks.push(assembleTask);\n }\n\n // Standard AGP injected signing properties — understood by AGP/Gradle for\n // any signing-aware build task without editing build.gradle.\n const signingArgs = [\n `-Pandroid.injected.signing.store.file=${resolve(options.keystorePath)}`,\n `-Pandroid.injected.signing.store.password=${options.keystorePassword}`,\n `-Pandroid.injected.signing.key.alias=${options.keyAlias}`,\n `-Pandroid.injected.signing.key.password=${options.keyPassword}`,\n ];\n\n // `--no-daemon`: build runners are ephemeral and re-run back-to-back. A\n // persistent Gradle daemon (with our raised heap) survives between builds and\n // stacks up, exhausting RAM on small runners. No-daemon keeps each build to a\n // single short-lived JVM.\n const args = [...tasks, \"--no-daemon\", ...signingArgs];\n\n const fullOutput: string[] = [];\n const onOutput = (chunk: string) => {\n fullOutput.push(chunk);\n if (options.onOutput) options.onOutput(chunk);\n };\n\n // Make gradlew executable (fresh checkouts may lack the +x bit).\n await chmod(join(projectDir, \"gradlew\"), 0o755).catch(() => {});\n\n // Raise the daemon's heap/metaspace unless the caller opted out (null).\n const jvmArgs =\n options.jvmArgs === undefined\n ? \"-Xmx3072m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8\"\n : options.jvmArgs;\n if (jvmArgs) {\n await ensureGradleMemory(projectDir, jvmArgs);\n }\n\n const result = await runGradle(projectDir, args, onOutput, options.signal);\n\n if (result.exitCode !== 0) {\n return {\n success: false,\n exitCode: result.exitCode,\n logContent: fullOutput.join(\"\"),\n };\n }\n\n // ── Locate artifacts ──────────────────────────────────────────────────\n\n let aabPath: string | undefined;\n let apkPath: string | undefined;\n\n if (options.outputType === \"aab\" || options.outputType === \"both\") {\n const bundleDir = join(\n projectDir,\n \"app\",\n \"build\",\n \"outputs\",\n \"bundle\",\n variant,\n );\n const found = await findFileWithExtension(bundleDir, \".aab\");\n if (found) aabPath = found;\n }\n\n if (options.outputType === \"apk\" || options.outputType === \"both\") {\n const apkDir = join(\n projectDir,\n \"app\",\n \"build\",\n \"outputs\",\n \"apk\",\n variant,\n );\n const found = await findFileWithExtension(apkDir, \".apk\");\n if (found) apkPath = found;\n }\n\n return {\n success: true,\n exitCode: 0,\n aabPath,\n apkPath,\n logContent: fullOutput.join(\"\"),\n };\n}\n"]}
@@ -1,2 +1,2 @@
1
- import '../enums-B609j2rb.cjs';
2
- export { D as DetectedValues, E as ExportOptionsPlistConfig, G as GymOptions, a as GymResult, X as XcodeBuildListOutput, b as buildApp, c as buildExportOptions, d as detectValues, g as generateExportOptionsPlistXml, w as writeExportOptionsPlist } from '../index-DrUpRXRG.cjs';
1
+ import '../enums-yXNVh3UI.cjs';
2
+ export { D as DetectedValues, E as ExportOptionsPlistConfig, G as GymOptions, a as GymResult, X as XcodeBuildListOutput, b as buildApp, c as buildExportOptions, d as detectValues, g as generateExportOptionsPlistXml, w as writeExportOptionsPlist } from '../index-B6-MJpO4.cjs';
@@ -1,2 +1,2 @@
1
- import '../enums-B609j2rb.js';
2
- export { D as DetectedValues, E as ExportOptionsPlistConfig, G as GymOptions, a as GymResult, X as XcodeBuildListOutput, b as buildApp, c as buildExportOptions, d as detectValues, g as generateExportOptionsPlistXml, w as writeExportOptionsPlist } from '../index-DImN9PWc.js';
1
+ import '../enums-yXNVh3UI.js';
2
+ export { D as DetectedValues, E as ExportOptionsPlistConfig, G as GymOptions, a as GymResult, X as XcodeBuildListOutput, b as buildApp, c as buildExportOptions, d as detectValues, g as generateExportOptionsPlistXml, w as writeExportOptionsPlist } from '../index-mEEB7An6.js';
@@ -0,0 +1,104 @@
1
+ import { A as AppleSession } from './apple-session-jUzBrql5.js';
2
+
3
+ /**
4
+ * App Privacy details ("nutrition labels") for an app in App Store Connect.
5
+ * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and
6
+ * Spaceship's AppDataUsage / AppDataUsagesPublishState models.
7
+ *
8
+ * The public App Store Connect API has no endpoint for privacy details — an
9
+ * API key cannot set them. Fastlane goes through the iris API that App Store
10
+ * Connect's own web UI uses, authenticated with an Apple ID session, and so
11
+ * does this: pass the AppleSession from `loginWithAppleId` / the App Release
12
+ * sign-in.
13
+ *
14
+ * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`
15
+ * works unchanged:
16
+ *
17
+ * [
18
+ * { "category": "EMAIL_ADDRESS", "purposes": ["APP_FUNCTIONALITY"], "data_protections": ["DATA_LINKED_TO_YOU"] },
19
+ * { "data_protections": ["DATA_NOT_COLLECTED"] } // an app that collects nothing
20
+ * ]
21
+ *
22
+ * As in Fastlane, the upload REPLACES everything: existing usages are deleted
23
+ * first, then the new ones are created, then the answers are published.
24
+ */
25
+
26
+ /** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */
27
+ declare const DATA_USAGE_CATEGORIES: readonly ["PAYMENT_INFORMATION", "CREDIT_AND_FRAUD", "OTHER_FINANCIAL_INFO", "PRECISE_LOCATION", "COARSE_LOCATION", "SENSITIVE_INFO", "PHYSICAL_ADDRESS", "EMAIL_ADDRESS", "NAME", "PHONE_NUMBER", "OTHER_CONTACT_INFO", "CONTACTS", "EMAILS_OR_TEXT_MESSAGES", "PHOTOS_OR_VIDEOS", "AUDIO", "GAMEPLAY_CONTENT", "CUSTOMER_SUPPORT", "OTHER_USER_CONTENT", "BROWSING_HISTORY", "SEARCH_HISTORY", "USER_ID", "DEVICE_ID", "PURCHASE_HISTORY", "PRODUCT_INTERACTION", "ADVERTISING_DATA", "OTHER_USAGE_DATA", "CRASH_DATA", "PERFORMANCE_DATA", "OTHER_DIAGNOSTIC_DATA", "OTHER_DATA", "HEALTH", "FITNESS"];
28
+ declare const DATA_USAGE_PURPOSES: readonly ["THIRD_PARTY_ADVERTISING", "DEVELOPERS_ADVERTISING", "ANALYTICS", "PRODUCT_PERSONALIZATION", "APP_FUNCTIONALITY", "OTHER_PURPOSES"];
29
+ declare const DATA_PROTECTIONS: readonly ["DATA_USED_TO_TRACK_YOU", "DATA_LINKED_TO_YOU", "DATA_NOT_LINKED_TO_YOU", "DATA_NOT_COLLECTED"];
30
+ type DataUsageCategory = "PAYMENT_INFORMATION" | "CREDIT_AND_FRAUD" | "OTHER_FINANCIAL_INFO" | "PRECISE_LOCATION" | "COARSE_LOCATION" | "SENSITIVE_INFO" | "PHYSICAL_ADDRESS" | "EMAIL_ADDRESS" | "NAME" | "PHONE_NUMBER" | "OTHER_CONTACT_INFO" | "CONTACTS" | "EMAILS_OR_TEXT_MESSAGES" | "PHOTOS_OR_VIDEOS" | "AUDIO" | "GAMEPLAY_CONTENT" | "CUSTOMER_SUPPORT" | "OTHER_USER_CONTENT" | "BROWSING_HISTORY" | "SEARCH_HISTORY" | "USER_ID" | "DEVICE_ID" | "PURCHASE_HISTORY" | "PRODUCT_INTERACTION" | "ADVERTISING_DATA" | "OTHER_USAGE_DATA" | "CRASH_DATA" | "PERFORMANCE_DATA" | "OTHER_DIAGNOSTIC_DATA" | "OTHER_DATA" | "HEALTH" | "FITNESS";
31
+ type DataUsagePurpose = "THIRD_PARTY_ADVERTISING" | "DEVELOPERS_ADVERTISING" | "ANALYTICS" | "PRODUCT_PERSONALIZATION" | "APP_FUNCTIONALITY" | "OTHER_PURPOSES";
32
+ type DataProtection = "DATA_USED_TO_TRACK_YOU" | "DATA_LINKED_TO_YOU" | "DATA_NOT_LINKED_TO_YOU" | "DATA_NOT_COLLECTED";
33
+ /** One entry of Fastlane's app_privacy_details.json. */
34
+ interface AppPrivacyUsage {
35
+ category?: DataUsageCategory;
36
+ purposes?: DataUsagePurpose[];
37
+ data_protections: DataProtection[];
38
+ }
39
+ interface UploadAppPrivacyOptions {
40
+ session: AppleSession;
41
+ /** App Store Connect app id (the numeric Apple ID). */
42
+ appId: string;
43
+ usages: AppPrivacyUsage[];
44
+ /** Leave the answers saved but unpublished (Fastlane's skip_publish). */
45
+ skipPublish?: boolean;
46
+ onLog?: (msg: string) => void;
47
+ }
48
+ interface UploadAppPrivacyResult {
49
+ deleted: number;
50
+ created: number;
51
+ published: boolean;
52
+ }
53
+ /**
54
+ * Point the session at the App Store Connect provider (team) that owns the app.
55
+ *
56
+ * An Apple ID in several teams signs in to whichever one it used last, and
57
+ * iris answers 404 for another team's app. Spaceship's `select_team` does the
58
+ * same switch: POST the provider id to the olympus session.
59
+ */
60
+ declare function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void>;
61
+ /** Existing privacy answers for an app. */
62
+ declare function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{
63
+ id: string;
64
+ }>>;
65
+ /** Spaceship AppDataUsage.create — relationships are sent only when given. */
66
+ declare function createAppDataUsage(session: AppleSession, input: {
67
+ appId: string;
68
+ category?: string | null;
69
+ purpose?: string | null;
70
+ dataProtection: string;
71
+ }): Promise<string>;
72
+ declare function deleteAppDataUsage(session: AppleSession, id: string): Promise<void>;
73
+ declare function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{
74
+ id: string;
75
+ published: boolean;
76
+ }>;
77
+ declare function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void>;
78
+ /** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */
79
+ declare function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult>;
80
+ /** Catch the answers App Store Connect would refuse, before deleting what is there. */
81
+ declare function validateUsages(usages: AppPrivacyUsage[]): void;
82
+
83
+ type index_AppPrivacyUsage = AppPrivacyUsage;
84
+ declare const index_DATA_PROTECTIONS: typeof DATA_PROTECTIONS;
85
+ declare const index_DATA_USAGE_CATEGORIES: typeof DATA_USAGE_CATEGORIES;
86
+ declare const index_DATA_USAGE_PURPOSES: typeof DATA_USAGE_PURPOSES;
87
+ type index_DataProtection = DataProtection;
88
+ type index_DataUsageCategory = DataUsageCategory;
89
+ type index_DataUsagePurpose = DataUsagePurpose;
90
+ type index_UploadAppPrivacyOptions = UploadAppPrivacyOptions;
91
+ type index_UploadAppPrivacyResult = UploadAppPrivacyResult;
92
+ declare const index_createAppDataUsage: typeof createAppDataUsage;
93
+ declare const index_deleteAppDataUsage: typeof deleteAppDataUsage;
94
+ declare const index_getAppDataUsagesPublishState: typeof getAppDataUsagesPublishState;
95
+ declare const index_listAppDataUsages: typeof listAppDataUsages;
96
+ declare const index_publishAppDataUsages: typeof publishAppDataUsages;
97
+ declare const index_selectProviderForApp: typeof selectProviderForApp;
98
+ declare const index_uploadAppPrivacyDetails: typeof uploadAppPrivacyDetails;
99
+ declare const index_validateUsages: typeof validateUsages;
100
+ declare namespace index {
101
+ export { type index_AppPrivacyUsage as AppPrivacyUsage, index_DATA_PROTECTIONS as DATA_PROTECTIONS, index_DATA_USAGE_CATEGORIES as DATA_USAGE_CATEGORIES, index_DATA_USAGE_PURPOSES as DATA_USAGE_PURPOSES, type index_DataProtection as DataProtection, type index_DataUsageCategory as DataUsageCategory, type index_DataUsagePurpose as DataUsagePurpose, type index_UploadAppPrivacyOptions as UploadAppPrivacyOptions, type index_UploadAppPrivacyResult as UploadAppPrivacyResult, index_createAppDataUsage as createAppDataUsage, index_deleteAppDataUsage as deleteAppDataUsage, index_getAppDataUsagesPublishState as getAppDataUsagesPublishState, index_listAppDataUsages as listAppDataUsages, index_publishAppDataUsages as publishAppDataUsages, index_selectProviderForApp as selectProviderForApp, index_uploadAppPrivacyDetails as uploadAppPrivacyDetails, index_validateUsages as validateUsages };
102
+ }
103
+
104
+ export { type AppPrivacyUsage as A, DATA_USAGE_CATEGORIES as D, type UploadAppPrivacyOptions as U, DATA_USAGE_PURPOSES as a, DATA_PROTECTIONS as b, type DataUsageCategory as c, type DataUsagePurpose as d, type DataProtection as e, type UploadAppPrivacyResult as f, createAppDataUsage as g, deleteAppDataUsage as h, index as i, getAppDataUsagesPublishState as j, listAppDataUsages as l, publishAppDataUsages as p, selectProviderForApp as s, uploadAppPrivacyDetails as u, validateUsages as v };