pakstr 0.8.3 → 0.8.5
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.
- package/dist/android/icon.js +3 -2
- package/dist/android/permissions.js +2 -1
- package/dist/android/splash.js +3 -2
- package/dist/commands/build.js +6 -5
- package/dist/core/assetPath.js +22 -0
- package/dist/core/buildContext.js +2 -0
- package/dist/runners/LocalGradleRunner.js +51 -26
- package/package.json +1 -1
package/dist/android/icon.js
CHANGED
|
@@ -7,12 +7,13 @@ exports.patchIcon = patchIcon;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const sharp_1 = __importDefault(require("sharp"));
|
|
10
|
-
|
|
10
|
+
const assetPath_1 = require("../core/assetPath");
|
|
11
|
+
async function patchIcon(androidRoot, iconPath, backgroundColor = "#FFFFFF", manifestDir = process.cwd()) {
|
|
11
12
|
if (!iconPath) {
|
|
12
13
|
console.log("ℹ️ No icon provided");
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
|
-
const absoluteIconPath =
|
|
16
|
+
const absoluteIconPath = (0, assetPath_1.resolveAssetPath)(iconPath, manifestDir);
|
|
16
17
|
if (!fs_1.default.existsSync(absoluteIconPath)) {
|
|
17
18
|
throw new Error(`❌ Icon not found: ${absoluteIconPath}`);
|
|
18
19
|
}
|
|
@@ -10,6 +10,7 @@ const permissionMap = {
|
|
|
10
10
|
internet: "android.permission.INTERNET",
|
|
11
11
|
camera: "android.permission.CAMERA",
|
|
12
12
|
notifications: "android.permission.POST_NOTIFICATIONS",
|
|
13
|
+
vibrate: "android.permission.VIBRATE",
|
|
13
14
|
};
|
|
14
15
|
function patchPermissions(androidRoot, manifest) {
|
|
15
16
|
if (!manifest.permissions?.length) {
|
|
@@ -18,7 +19,7 @@ function patchPermissions(androidRoot, manifest) {
|
|
|
18
19
|
const file = path_1.default.join(androidRoot, "app/src/main/AndroidManifest.xml");
|
|
19
20
|
let xml = fs_1.default.readFileSync(file, "utf-8");
|
|
20
21
|
for (const perm of manifest.permissions) {
|
|
21
|
-
const androidPermission = permissionMap[perm];
|
|
22
|
+
const androidPermission = permissionMap[perm.trim().toLowerCase()];
|
|
22
23
|
if (!androidPermission) {
|
|
23
24
|
console.warn(`⚠️ Unknown permission: ${perm}`);
|
|
24
25
|
continue;
|
package/dist/android/splash.js
CHANGED
|
@@ -7,12 +7,13 @@ exports.patchSplash = patchSplash;
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const sharp_1 = __importDefault(require("sharp"));
|
|
10
|
-
|
|
10
|
+
const assetPath_1 = require("../core/assetPath");
|
|
11
|
+
async function patchSplash(androidRoot, splashPath, backgroundColor, manifestDir = process.cwd()) {
|
|
11
12
|
if (!splashPath) {
|
|
12
13
|
console.log("ℹ️ No splash provided");
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
|
-
const absolutePath =
|
|
16
|
+
const absolutePath = (0, assetPath_1.resolveAssetPath)(splashPath, manifestDir);
|
|
16
17
|
if (!fs_1.default.existsSync(absolutePath)) {
|
|
17
18
|
throw new Error(`❌ Splash not found: ${absolutePath}`);
|
|
18
19
|
}
|
package/dist/commands/build.js
CHANGED
|
@@ -51,7 +51,7 @@ async function buildCommand(args) {
|
|
|
51
51
|
? (workspace = (0, releaseWorkspace_1.createReleaseWorkspace)(templateRoot)).androidRoot
|
|
52
52
|
: templateRoot;
|
|
53
53
|
console.log("📱 Android:", androidRoot);
|
|
54
|
-
await prepareAndroidProject(androidRoot, ctx.dist, manifest, appName);
|
|
54
|
+
await prepareAndroidProject(androidRoot, ctx.dist, manifest, appName, ctx.manifestDir);
|
|
55
55
|
if (signingInput) {
|
|
56
56
|
signing = (0, releaseSigning_1.createReleaseSigningContext)(signingInput);
|
|
57
57
|
signingInput.keystoreBase64 = "";
|
|
@@ -69,7 +69,8 @@ async function buildCommand(args) {
|
|
|
69
69
|
signing,
|
|
70
70
|
});
|
|
71
71
|
if (mode === "release" && !result.verification) {
|
|
72
|
-
|
|
72
|
+
console.warn("⚠️ Release verification evidence unavailable locally.");
|
|
73
|
+
console.warn("ℹ️ CI/Docker release verification will be used.");
|
|
73
74
|
}
|
|
74
75
|
stagedPath = stageArtifact(result.artifactPath, finalPath);
|
|
75
76
|
}
|
|
@@ -109,7 +110,7 @@ async function buildCommand(args) {
|
|
|
109
110
|
console.log("📦 Output:", finalPath);
|
|
110
111
|
openFolder(finalPath);
|
|
111
112
|
}
|
|
112
|
-
async function prepareAndroidProject(androidRoot, distPath, manifest, appName) {
|
|
113
|
+
async function prepareAndroidProject(androidRoot, distPath, manifest, appName, manifestDir) {
|
|
113
114
|
const assetsTarget = path_1.default.join(androidRoot, "app/src/main/assets/www");
|
|
114
115
|
if (!fs_1.default.existsSync(distPath)) {
|
|
115
116
|
throw new Error("Web assets not found");
|
|
@@ -121,10 +122,10 @@ async function prepareAndroidProject(androidRoot, distPath, manifest, appName) {
|
|
|
121
122
|
(0, gradle_1.patchGradle)(androidRoot, manifest);
|
|
122
123
|
(0, branding_1.patchAppName)(androidRoot, appName);
|
|
123
124
|
if (manifest.ui?.icon) {
|
|
124
|
-
await (0, icon_1.patchIcon)(androidRoot, manifest.ui.icon, manifest.backgroundColor ?? "#FFFFFF");
|
|
125
|
+
await (0, icon_1.patchIcon)(androidRoot, manifest.ui.icon, manifest.backgroundColor ?? "#FFFFFF", manifestDir);
|
|
125
126
|
}
|
|
126
127
|
if (manifest.ui?.splash) {
|
|
127
|
-
await (0, splash_1.patchSplash)(androidRoot, manifest.ui.splash.image, manifest.ui.splash.background ?? "#FFFFFF");
|
|
128
|
+
await (0, splash_1.patchSplash)(androidRoot, manifest.ui.splash.image, manifest.ui.splash.background ?? "#FFFFFF", manifestDir);
|
|
128
129
|
}
|
|
129
130
|
(0, permissions_1.patchPermissions)(androidRoot, manifest);
|
|
130
131
|
(0, generatedProjectVerification_1.verifyGeneratedAndroidProject)(androidRoot, {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveAssetPath = resolveAssetPath;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
function resolveAssetPath(assetPath, manifestDir) {
|
|
10
|
+
if (path_1.default.isAbsolute(assetPath)) {
|
|
11
|
+
return assetPath;
|
|
12
|
+
}
|
|
13
|
+
const manifestRelativePath = path_1.default.resolve(manifestDir, assetPath);
|
|
14
|
+
if (fs_1.default.existsSync(manifestRelativePath)) {
|
|
15
|
+
return manifestRelativePath;
|
|
16
|
+
}
|
|
17
|
+
const cwdRelativePath = path_1.default.resolve(process.cwd(), assetPath);
|
|
18
|
+
if (fs_1.default.existsSync(cwdRelativePath)) {
|
|
19
|
+
return cwdRelativePath;
|
|
20
|
+
}
|
|
21
|
+
return manifestRelativePath;
|
|
22
|
+
}
|
|
@@ -92,6 +92,8 @@ function createBuildContext(args) {
|
|
|
92
92
|
const androidRoot = path_1.default.resolve(process.cwd(), "android-template");
|
|
93
93
|
return {
|
|
94
94
|
manifest,
|
|
95
|
+
manifestPath,
|
|
96
|
+
manifestDir: path_1.default.dirname(manifestPath),
|
|
95
97
|
dist: path_1.default.resolve(web),
|
|
96
98
|
out,
|
|
97
99
|
androidRoot,
|
|
@@ -25,12 +25,17 @@ class LocalGradleRunner {
|
|
|
25
25
|
env: (0, releaseSigning_1.removeSigningVariables)(process.env),
|
|
26
26
|
streamOutput: true,
|
|
27
27
|
});
|
|
28
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
artifactPath: requireApk(androidRoot, "debug"),
|
|
30
|
+
};
|
|
29
31
|
}
|
|
30
32
|
const signing = requireSigning(request.signing);
|
|
31
33
|
const secrets = signingSecrets(signing);
|
|
32
34
|
const gradleEnv = (0, releaseSigning_1.createGradleSigningEnvironment)(signing);
|
|
33
|
-
(0, process_1.runProcess)(gradlewPath, [
|
|
35
|
+
(0, process_1.runProcess)(gradlewPath, [
|
|
36
|
+
"assembleRelease",
|
|
37
|
+
"--no-daemon",
|
|
38
|
+
], {
|
|
34
39
|
cwd: androidRoot,
|
|
35
40
|
env: gradleEnv,
|
|
36
41
|
secrets,
|
|
@@ -40,32 +45,43 @@ class LocalGradleRunner {
|
|
|
40
45
|
let verification;
|
|
41
46
|
try {
|
|
42
47
|
const executor = createLocalVerificationExecutor(signing);
|
|
43
|
-
verification =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
verification =
|
|
49
|
+
(0, releaseVerification_1.verifyReleaseApk)({
|
|
50
|
+
artifactPath,
|
|
51
|
+
expectedMetadata: request.expectedMetadata,
|
|
52
|
+
signing,
|
|
53
|
+
executor,
|
|
54
|
+
});
|
|
49
55
|
}
|
|
50
56
|
catch (error) {
|
|
51
|
-
|
|
52
|
-
"Required Android verification tool not found",
|
|
53
|
-
"Android cmdline-tools directory not found",
|
|
54
|
-
"Android build-tools directory not found",
|
|
55
|
-
];
|
|
56
|
-
if (error instanceof Error &&
|
|
57
|
-
localToolErrors.some(message => error.message.startsWith(message))) {
|
|
57
|
+
if (isMissingLocalVerificationTool(error)) {
|
|
58
58
|
console.warn("⚠️ Local release verification skipped: Android verification tools are unavailable.");
|
|
59
59
|
console.warn("ℹ️ Full release verification will still run in Docker/CI.");
|
|
60
|
+
verification = undefined;
|
|
60
61
|
}
|
|
61
62
|
else {
|
|
62
63
|
throw error;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
artifactPath,
|
|
68
|
+
verification,
|
|
69
|
+
};
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
exports.LocalGradleRunner = LocalGradleRunner;
|
|
73
|
+
function isMissingLocalVerificationTool(error) {
|
|
74
|
+
if (!(error instanceof Error)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const messages = [
|
|
78
|
+
"verification tool",
|
|
79
|
+
"cmdline-tools",
|
|
80
|
+
"build-tools directory",
|
|
81
|
+
"Required Android verification tool",
|
|
82
|
+
];
|
|
83
|
+
return messages.some(message => error.message.includes(message));
|
|
84
|
+
}
|
|
69
85
|
function createLocalVerificationExecutor(signing) {
|
|
70
86
|
const androidHome = process.env.ANDROID_HOME ??
|
|
71
87
|
process.env.ANDROID_SDK_ROOT ??
|
|
@@ -75,23 +91,28 @@ function createLocalVerificationExecutor(signing) {
|
|
|
75
91
|
run(tool, args, env = {}) {
|
|
76
92
|
const command = resolveTool(tool, androidHome);
|
|
77
93
|
return (0, process_1.runProcess)(command, args, {
|
|
78
|
-
env: {
|
|
94
|
+
env: {
|
|
95
|
+
...process.env,
|
|
96
|
+
...env,
|
|
97
|
+
},
|
|
79
98
|
secrets,
|
|
80
99
|
});
|
|
81
100
|
},
|
|
82
101
|
};
|
|
83
102
|
}
|
|
84
103
|
function resolveTool(tool, androidHome) {
|
|
85
|
-
if (tool === "keytool")
|
|
104
|
+
if (tool === "keytool") {
|
|
86
105
|
return "keytool";
|
|
106
|
+
}
|
|
87
107
|
if (tool === "apkanalyzer") {
|
|
88
108
|
const cmdlineTools = path_1.default.join(androidHome, "cmdline-tools");
|
|
89
109
|
if (!fs_1.default.existsSync(cmdlineTools)) {
|
|
90
110
|
throw new Error(`Android cmdline-tools directory not found: ${cmdlineTools}`);
|
|
91
111
|
}
|
|
92
|
-
const versions = fs_1.default
|
|
93
|
-
.
|
|
94
|
-
|
|
112
|
+
const versions = fs_1.default.readdirSync(cmdlineTools)
|
|
113
|
+
.sort((a, b) => b.localeCompare(a, undefined, {
|
|
114
|
+
numeric: true,
|
|
115
|
+
}));
|
|
95
116
|
const analyzer = versions
|
|
96
117
|
.map(version => path_1.default.join(cmdlineTools, version, "bin", "apkanalyzer"))
|
|
97
118
|
.find(candidate => fs_1.default.existsSync(candidate));
|
|
@@ -104,10 +125,13 @@ function resolveTool(tool, androidHome) {
|
|
|
104
125
|
if (!fs_1.default.existsSync(buildToolsDir)) {
|
|
105
126
|
throw new Error(`Android build-tools directory not found: ${buildToolsDir}`);
|
|
106
127
|
}
|
|
107
|
-
const versions = fs_1.default
|
|
108
|
-
.
|
|
109
|
-
|
|
110
|
-
|
|
128
|
+
const versions = fs_1.default.readdirSync(buildToolsDir)
|
|
129
|
+
.sort((a, b) => b.localeCompare(a, undefined, {
|
|
130
|
+
numeric: true,
|
|
131
|
+
}));
|
|
132
|
+
const executable = tool === "aapt"
|
|
133
|
+
? "aapt"
|
|
134
|
+
: "apksigner";
|
|
111
135
|
const resolved = versions
|
|
112
136
|
.map(version => path_1.default.join(buildToolsDir, version, executable))
|
|
113
137
|
.find(candidate => fs_1.default.existsSync(candidate));
|
|
@@ -118,7 +142,8 @@ function resolveTool(tool, androidHome) {
|
|
|
118
142
|
}
|
|
119
143
|
function requireApk(androidRoot, mode) {
|
|
120
144
|
const artifactPath = path_1.default.join(androidRoot, "app", "build", "outputs", "apk", mode, `app-${mode}.apk`);
|
|
121
|
-
if (!fs_1.default.existsSync(artifactPath) ||
|
|
145
|
+
if (!fs_1.default.existsSync(artifactPath) ||
|
|
146
|
+
!fs_1.default.lstatSync(artifactPath).isFile()) {
|
|
122
147
|
throw new Error(`APK not found after Gradle build: ${artifactPath}`);
|
|
123
148
|
}
|
|
124
149
|
return artifactPath;
|