pakstr 0.8.7 → 0.9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pakstr",
3
- "version": "0.8.7",
3
+ "version": "0.9.0",
4
4
  "description": "CLI for packaging Nostr web apps into Android APKs",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",
@@ -41,12 +41,18 @@
41
41
  ],
42
42
  "license": "ISC",
43
43
  "devDependencies": {
44
+ "@types/debug": "^4.1.13",
45
+ "@types/js-yaml": "^4.0.9",
44
46
  "@types/node": "^26.1.0",
45
47
  "@types/unzipper": "^0.10.11",
46
48
  "typescript": "^6.0.3"
47
49
  },
48
50
  "dependencies": {
51
+ "@scure/base": "^2.3.0",
52
+ "applesauce-core": "^6.2.0",
53
+ "applesauce-signers": "^6.2.2",
49
54
  "fs-extra": "^11.3.6",
55
+ "js-yaml": "^5.3.0",
50
56
  "node-fetch": "^3.3.2",
51
57
  "sharp": "^0.35.3",
52
58
  "unzipper": "^0.12.5"
@@ -1,164 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.verifyReleaseApk = verifyReleaseApk;
4
- exports.parseApkSignerFingerprints = parseApkSignerFingerprints;
5
- exports.parseKeystoreFingerprints = parseKeystoreFingerprints;
6
- exports.parseAaptBadging = parseAaptBadging;
7
- const crypto_1 = require("crypto");
8
- const releaseSigning_1 = require("../core/releaseSigning");
9
- function verifyReleaseApk(input) {
10
- const signerResult = input.executor.run("apksigner", [
11
- "verify",
12
- "--print-certs",
13
- input.artifactPath,
14
- ]);
15
- const signerFingerprints = parseApkSignerFingerprints(signerResult.stdout);
16
- if (signerFingerprints.length !== 1) {
17
- throw new Error(`Release APK must have exactly one current signer; found ${signerFingerprints.length}`);
18
- }
19
- const keytoolEnv = {
20
- [releaseSigning_1.PUBLIC_SIGNING_ENV.keystorePassword]: input.signing.storePassword,
21
- };
22
- const keytoolResult = input.executor.run("keytool", [
23
- "-list",
24
- "-rfc",
25
- "-keystore",
26
- input.toolKeystorePath ?? input.signing.keystorePath,
27
- "-storepass:env",
28
- releaseSigning_1.PUBLIC_SIGNING_ENV.keystorePassword,
29
- ], keytoolEnv);
30
- const keystoreFingerprints = parseKeystoreFingerprints(keytoolResult.stdout);
31
- const matchingEntries = keystoreFingerprints.filter(fingerprint => fingerprint === signerFingerprints[0]);
32
- if (matchingEntries.length !== 1) {
33
- throw new Error(`Release APK signer must match exactly one certificate in the supplied keystore; found ${matchingEntries.length}`);
34
- }
35
- const analyzerMetadata = {
36
- applicationId: readAnalyzerValue(input, "application-id"),
37
- versionCode: parseVersionCode(readAnalyzerValue(input, "version-code")),
38
- versionName: readAnalyzerValue(input, "version-name"),
39
- };
40
- const badging = parseAaptBadging(input.executor.run("aapt", ["dump", "badging", input.artifactPath]).stdout);
41
- assertMetadataField("Application ID", analyzerMetadata.applicationId, input.expectedMetadata.applicationId);
42
- assertMetadataField("versionCode", analyzerMetadata.versionCode, input.expectedMetadata.versionCode);
43
- assertMetadataField("versionName", analyzerMetadata.versionName, input.expectedMetadata.versionName);
44
- assertMetadataField("aapt Application ID", badging.applicationId, analyzerMetadata.applicationId);
45
- assertMetadataField("aapt versionCode", badging.versionCode, analyzerMetadata.versionCode);
46
- assertMetadataField("aapt versionName", badging.versionName, analyzerMetadata.versionName);
47
- assertMetadataField("app label", badging.appLabel, input.expectedMetadata.appLabel);
48
- return {
49
- signatureVerified: true,
50
- signerMatched: true,
51
- expectedMetadata: input.expectedMetadata,
52
- actualMetadata: {
53
- applicationId: analyzerMetadata.applicationId,
54
- versionCode: analyzerMetadata.versionCode,
55
- versionName: analyzerMetadata.versionName,
56
- appLabel: badging.appLabel,
57
- },
58
- tools: {
59
- signature: "apksigner",
60
- signer: "keytool",
61
- manifest: "apkanalyzer",
62
- badging: "aapt",
63
- },
64
- };
65
- }
66
- function parseApkSignerFingerprints(output) {
67
- const fingerprints = output
68
- .split(/\r?\n/)
69
- .map(line => line.match(/Signer #\d+ certificate SHA-256 digest:\s*([0-9a-fA-F]+)/)?.[1])
70
- .filter((value) => value !== undefined)
71
- .map(normalizeFingerprint);
72
- return [...new Set(fingerprints)];
73
- }
74
- function parseKeystoreFingerprints(output) {
75
- const certificates = output.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g);
76
- if (!certificates?.length) {
77
- throw new Error("No certificate-bearing entries found in supplied keystore");
78
- }
79
- return certificates.map(pem => {
80
- const certificate = new crypto_1.X509Certificate(pem);
81
- return (0, crypto_1.createHash)("sha256").update(certificate.raw).digest("hex");
82
- });
83
- }
84
- function parseAaptBadging(output) {
85
- const lines = output.split(/\r?\n/);
86
- const packageLines = lines.filter(line => line.startsWith("package: "));
87
- const labelLines = lines.filter(line => line.startsWith("application-label:"));
88
- if (packageLines.length !== 1) {
89
- throw new Error(`Expected exactly one aapt package line, found ${packageLines.length}`);
90
- }
91
- if (labelLines.length !== 1) {
92
- throw new Error(`Expected exactly one default aapt application label, found ${labelLines.length}`);
93
- }
94
- const packageLine = packageLines[0];
95
- const applicationId = readAaptAttribute(packageLine, "name");
96
- const versionCode = parseVersionCode(readAaptAttribute(packageLine, "versionCode"));
97
- const versionName = readAaptAttribute(packageLine, "versionName");
98
- const appLabel = parseQuotedAaptValue(labelLines[0], "application-label");
99
- return {
100
- applicationId,
101
- versionCode,
102
- versionName,
103
- appLabel,
104
- };
105
- }
106
- function readAnalyzerValue(input, verb) {
107
- const result = input.executor.run("apkanalyzer", [
108
- "manifest",
109
- verb,
110
- input.artifactPath,
111
- ]);
112
- const values = result.stdout
113
- .split(/\r?\n/)
114
- .map(value => value.trim())
115
- .filter(Boolean);
116
- if (values.length !== 1) {
117
- throw new Error(`Unable to derive one unambiguous ${verb} from release APK`);
118
- }
119
- return values[0];
120
- }
121
- function parseQuotedAaptValue(line, field) {
122
- const pattern = new RegExp(`^${field}:'((?:\\\\.|[^'])*)'$`);
123
- const match = pattern.exec(line);
124
- if (!match || match[1] === undefined) {
125
- throw new Error(`Unable to derive one unambiguous aapt ${field}`);
126
- }
127
- return decodeAaptEscapes(match[1]);
128
- }
129
- function readAaptAttribute(line, name) {
130
- const pattern = new RegExp(`${name}='((?:\\\\.|[^'])*)'`);
131
- const match = pattern.exec(line);
132
- if (!match || match[1] === undefined) {
133
- throw new Error(`Unable to derive one unambiguous aapt ${name}`);
134
- }
135
- return decodeAaptEscapes(match[1]);
136
- }
137
- function decodeAaptEscapes(value) {
138
- return value.replace(/\\(.)/gs, (_match, escaped) => {
139
- switch (escaped) {
140
- case "n":
141
- return "\n";
142
- case "r":
143
- return "\r";
144
- case "t":
145
- return "\t";
146
- default:
147
- return escaped;
148
- }
149
- });
150
- }
151
- function parseVersionCode(value) {
152
- if (!/^\d+$/.test(value)) {
153
- throw new Error(`APK versionCode is not an integer: ${value}`);
154
- }
155
- return Number(value);
156
- }
157
- function assertMetadataField(field, actual, expected) {
158
- if (actual !== expected) {
159
- throw new Error(`Release APK ${field} mismatch: expected ${expected}, received ${actual}`);
160
- }
161
- }
162
- function normalizeFingerprint(value) {
163
- return value.replace(/[^0-9a-fA-F]/g, "").toLowerCase();
164
- }
package/dist/config.js DELETED
@@ -1,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TEMPLATE_URL = void 0;
4
- exports.TEMPLATE_URL = "https://git.nostrdev.com/stuff/pakstr/-/archive/main/pakstr-main.zip";
@@ -1,102 +0,0 @@
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.createBuildContext = createBuildContext;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_1 = __importDefault(require("fs"));
9
- const manifest_1 = require("./manifest");
10
- // -----------------------------
11
- // CONFIG LOADER
12
- // -----------------------------
13
- function loadConfig() {
14
- const configPath = path_1.default.resolve(process.cwd(), "nostr.config.json");
15
- if (!fs_1.default.existsSync(configPath)) {
16
- return null;
17
- }
18
- try {
19
- return JSON.parse(fs_1.default.readFileSync(configPath, "utf-8"));
20
- }
21
- catch (e) {
22
- throw new Error("❌ Invalid nostr.config.json");
23
- }
24
- }
25
- function createBuildContext(args) {
26
- const getArg = (key) => {
27
- const i = args.indexOf(key);
28
- return i !== -1 ? args[i + 1] : null;
29
- };
30
- function resolvePath(p) {
31
- if (!p)
32
- return null;
33
- // absolute path
34
- if (path_1.default.isAbsolute(p)) {
35
- return p;
36
- }
37
- // try cwd
38
- const cwdPath = path_1.default.resolve(process.cwd(), p);
39
- if (fs_1.default.existsSync(cwdPath)) {
40
- return cwdPath;
41
- }
42
- // try one level up (VERY IMPORTANT for your case)
43
- const parentPath = path_1.default.resolve(process.cwd(), "..", p);
44
- if (fs_1.default.existsSync(parentPath)) {
45
- return parentPath;
46
- }
47
- return cwdPath;
48
- }
49
- const mode = args.includes("--release") ? "release" : "debug";
50
- // -----------------------------
51
- // 1. LOAD CONFIG (OPTIONAL)
52
- // -----------------------------
53
- const config = loadConfig();
54
- // -----------------------------
55
- // 2. RESOLVE INPUTS (PRIORITY ORDER)
56
- // args > config > error
57
- // -----------------------------
58
- const webRaw = getArg("--web") ?? config?.web;
59
- const manifestPathRaw = getArg("--manifest") ?? config?.manifest;
60
- const outPathRaw = getArg("--out") ?? config?.out;
61
- const web = resolvePath(webRaw);
62
- const manifestPath = resolvePath(manifestPathRaw);
63
- const outPath = resolvePath(outPathRaw);
64
- // -----------------------------
65
- // 3. VALIDATION (STRICT)
66
- // -----------------------------
67
- if (!web) {
68
- throw new Error("❌ Missing web path (--web or nostr.config.json)");
69
- }
70
- if (!manifestPath) {
71
- throw new Error("❌ Missing manifest path (--manifest or nostr.config.json)");
72
- }
73
- if (!fs_1.default.existsSync(web)) {
74
- throw new Error(`❌ Web folder not found: ${web}`);
75
- }
76
- if (!fs_1.default.existsSync(manifestPath)) {
77
- throw new Error(`❌ Manifest not found: ${manifestPath}`);
78
- }
79
- // -----------------------------
80
- // 4. LOAD MANIFEST
81
- // -----------------------------
82
- const manifest = (0, manifest_1.loadManifest)(manifestPath);
83
- // -----------------------------
84
- // 5. OUTPUT PATH
85
- // -----------------------------
86
- const out = outPath
87
- ? path_1.default.resolve(outPath)
88
- : path_1.default.join(process.cwd(), "build/app.apk");
89
- // -----------------------------
90
- // 6. ANDROID ROOT
91
- // -----------------------------
92
- const androidRoot = path_1.default.resolve(process.cwd(), "android-template");
93
- return {
94
- manifest,
95
- manifestPath,
96
- manifestDir: path_1.default.dirname(manifestPath),
97
- dist: path_1.default.resolve(web),
98
- out,
99
- androidRoot,
100
- mode,
101
- };
102
- }
@@ -1,24 +0,0 @@
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.loadConfig = loadConfig;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function loadConfig(cwd) {
10
- const configPath = path_1.default.join(cwd, "nostr.config.json");
11
- if (!fs_1.default.existsSync(configPath)) {
12
- return {
13
- builder: "local"
14
- };
15
- }
16
- const json = JSON.parse(fs_1.default.readFileSync(configPath, "utf-8"));
17
- const builder = json.builder === "docker"
18
- ? "docker"
19
- : "local";
20
- return {
21
- builder,
22
- dockerImage: json.dockerImage
23
- };
24
- }
@@ -1,17 +0,0 @@
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.copyFile = copyFile;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function copyFile(source, destination) {
10
- const dir = path_1.default.dirname(destination);
11
- if (!fs_1.default.existsSync(dir)) {
12
- fs_1.default.mkdirSync(dir, {
13
- recursive: true
14
- });
15
- }
16
- fs_1.default.copyFileSync(source, destination);
17
- }
@@ -1,47 +0,0 @@
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.loadManifest = loadManifest;
7
- const fs_1 = __importDefault(require("fs"));
8
- function loadManifest(path) {
9
- if (!fs_1.default.existsSync(path)) {
10
- throw new Error(`❌ Manifest not found: ${path}`);
11
- }
12
- const manifest = JSON.parse(fs_1.default.readFileSync(path, "utf-8"));
13
- validateManifest(manifest);
14
- return manifest;
15
- }
16
- function validateManifest(m) {
17
- if (!m.appId)
18
- throw new Error("❌ appId is required");
19
- const appIdPattern = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/;
20
- if (m.appId.length < 3 ||
21
- m.appId.length > 255 ||
22
- !appIdPattern.test(m.appId)) {
23
- throw new Error("❌ appId must be a lowercase reverse-domain Android Application ID");
24
- }
25
- const debugAppId = `${m.appId}.debug`;
26
- if (debugAppId.length > 255 || !appIdPattern.test(debugAppId)) {
27
- throw new Error("❌ appId is too long to derive the debug Application ID");
28
- }
29
- if (!m.appName)
30
- throw new Error("❌ appName is required");
31
- if (/[\r\n]/.test(m.appName)) {
32
- throw new Error("❌ appName must not contain line breaks");
33
- }
34
- if (!m.versionName)
35
- throw new Error("❌ versionName is required");
36
- if (/[\r\n"\\]/.test(m.versionName)) {
37
- throw new Error("❌ versionName must not contain line breaks, quotes, or backslashes");
38
- }
39
- if (m.versionCode === undefined)
40
- throw new Error("❌ versionCode is required");
41
- if (!Number.isInteger(m.versionCode) || m.versionCode <= 0) {
42
- throw new Error("❌ versionCode must be a positive integer");
43
- }
44
- if (m.ui?.splash && !m.ui.splash.image) {
45
- throw new Error("❌ splash.image is required");
46
- }
47
- }
@@ -1,134 +0,0 @@
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.INTERNAL_KEYSTORE_PATH_ENV = exports.PUBLIC_SIGNING_ENV = void 0;
7
- exports.readReleaseSigningInput = readReleaseSigningInput;
8
- exports.createReleaseSigningContext = createReleaseSigningContext;
9
- exports.removeSigningVariables = removeSigningVariables;
10
- exports.createGradleSigningEnvironment = createGradleSigningEnvironment;
11
- const fs_1 = __importDefault(require("fs"));
12
- const os_1 = __importDefault(require("os"));
13
- const path_1 = __importDefault(require("path"));
14
- exports.PUBLIC_SIGNING_ENV = {
15
- keystoreBase64: "PAKSTR_ANDROID_KEYSTORE_BASE64",
16
- keystorePassword: "PAKSTR_ANDROID_KEYSTORE_PASSWORD",
17
- keyAlias: "PAKSTR_ANDROID_KEY_ALIAS",
18
- keyPassword: "PAKSTR_ANDROID_KEY_PASSWORD",
19
- };
20
- exports.INTERNAL_KEYSTORE_PATH_ENV = "PAKSTR_ANDROID_KEYSTORE_PATH";
21
- const MAX_KEYSTORE_BYTES = 16 * 1024 * 1024;
22
- const CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
23
- function readReleaseSigningInput(env = process.env) {
24
- const keystoreBase64 = requireValue(env, exports.PUBLIC_SIGNING_ENV.keystoreBase64);
25
- const storePassword = requireValue(env, exports.PUBLIC_SIGNING_ENV.keystorePassword);
26
- const keyAlias = requireValue(env, exports.PUBLIC_SIGNING_ENV.keyAlias);
27
- const keyPassword = requireValue(env, exports.PUBLIC_SIGNING_ENV.keyPassword);
28
- validateCanonicalBase64(keystoreBase64);
29
- return {
30
- keystoreBase64,
31
- storePassword,
32
- keyAlias,
33
- keyPassword,
34
- };
35
- }
36
- function createReleaseSigningContext(input, temporaryRoot = os_1.default.tmpdir()) {
37
- let decoded = decodeKeystore(input.keystoreBase64);
38
- fs_1.default.mkdirSync(temporaryRoot, { recursive: true, mode: 0o700 });
39
- const signingDir = fs_1.default.mkdtempSync(path_1.default.join(temporaryRoot, "pakstr-signing-"));
40
- const keystorePath = path_1.default.join(signingDir, "release.keystore");
41
- let cleaned = false;
42
- try {
43
- fs_1.default.chmodSync(signingDir, 0o700);
44
- fs_1.default.writeFileSync(keystorePath, decoded, {
45
- flag: "wx",
46
- mode: 0o600,
47
- });
48
- verifyProtectedKeystore(signingDir, keystorePath, decoded.length);
49
- }
50
- catch (error) {
51
- fs_1.default.rmSync(signingDir, { recursive: true, force: true });
52
- throw error;
53
- }
54
- finally {
55
- decoded.fill(0);
56
- decoded = Buffer.alloc(0);
57
- }
58
- return Object.freeze({
59
- keystorePath,
60
- storePassword: input.storePassword,
61
- keyAlias: input.keyAlias,
62
- keyPassword: input.keyPassword,
63
- cleanup() {
64
- if (cleaned)
65
- return;
66
- fs_1.default.rmSync(signingDir, { recursive: true, force: true, maxRetries: 2 });
67
- if (fs_1.default.existsSync(signingDir)) {
68
- throw new Error(`Failed to remove temporary signing directory: ${signingDir}`);
69
- }
70
- cleaned = true;
71
- },
72
- });
73
- }
74
- function removeSigningVariables(env) {
75
- const sanitized = { ...env };
76
- delete sanitized[exports.PUBLIC_SIGNING_ENV.keystoreBase64];
77
- delete sanitized[exports.PUBLIC_SIGNING_ENV.keystorePassword];
78
- delete sanitized[exports.PUBLIC_SIGNING_ENV.keyAlias];
79
- delete sanitized[exports.PUBLIC_SIGNING_ENV.keyPassword];
80
- delete sanitized[exports.INTERNAL_KEYSTORE_PATH_ENV];
81
- return sanitized;
82
- }
83
- function createGradleSigningEnvironment(context, env = process.env, keystorePath = context.keystorePath) {
84
- return {
85
- ...removeSigningVariables(env),
86
- [exports.INTERNAL_KEYSTORE_PATH_ENV]: keystorePath,
87
- [exports.PUBLIC_SIGNING_ENV.keystorePassword]: context.storePassword,
88
- [exports.PUBLIC_SIGNING_ENV.keyAlias]: context.keyAlias,
89
- [exports.PUBLIC_SIGNING_ENV.keyPassword]: context.keyPassword,
90
- };
91
- }
92
- function requireValue(env, name) {
93
- const value = env[name];
94
- if (value === undefined || value.length === 0) {
95
- throw new Error(`${name} is required and must not be empty for release builds`);
96
- }
97
- return value;
98
- }
99
- function validateCanonicalBase64(value) {
100
- if (!CANONICAL_BASE64.test(value)) {
101
- throw new Error(`${exports.PUBLIC_SIGNING_ENV.keystoreBase64} must be canonical single-line RFC 4648 base64`);
102
- }
103
- const decodedLength = Buffer.byteLength(value, "base64");
104
- if (decodedLength === 0) {
105
- throw new Error(`${exports.PUBLIC_SIGNING_ENV.keystoreBase64} decodes to an empty keystore`);
106
- }
107
- if (decodedLength > MAX_KEYSTORE_BYTES) {
108
- throw new Error(`${exports.PUBLIC_SIGNING_ENV.keystoreBase64} exceeds the 16 MiB decoded size limit`);
109
- }
110
- }
111
- function decodeKeystore(value) {
112
- const decoded = Buffer.from(value, "base64");
113
- if (decoded.toString("base64") !== value) {
114
- decoded.fill(0);
115
- throw new Error(`${exports.PUBLIC_SIGNING_ENV.keystoreBase64} is not canonical base64`);
116
- }
117
- return decoded;
118
- }
119
- function verifyProtectedKeystore(signingDir, keystorePath, expectedSize) {
120
- const dirStat = fs_1.default.lstatSync(signingDir);
121
- const fileStat = fs_1.default.lstatSync(keystorePath);
122
- if (!dirStat.isDirectory() || dirStat.isSymbolicLink()) {
123
- throw new Error("Temporary signing directory is not a real directory");
124
- }
125
- if (!fileStat.isFile() || fileStat.isSymbolicLink()) {
126
- throw new Error("Temporary keystore is not a regular file");
127
- }
128
- if ((dirStat.mode & 0o777) !== 0o700 || (fileStat.mode & 0o777) !== 0o600) {
129
- throw new Error("Temporary signing storage does not have owner-only permissions");
130
- }
131
- if (fileStat.size !== expectedSize) {
132
- throw new Error("Temporary keystore size does not match decoded input");
133
- }
134
- }
@@ -1,20 +0,0 @@
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.resolveProjectInputs = resolveProjectInputs;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function resolveProjectInputs() {
10
- const cwd = process.cwd();
11
- const dist = path_1.default.join(cwd, "dist");
12
- const manifest = path_1.default.join(cwd, "app.manifest.json");
13
- if (!fs_1.default.existsSync(dist)) {
14
- throw new Error("❌ Missing dist folder. Expected: ./dist");
15
- }
16
- if (!fs_1.default.existsSync(manifest)) {
17
- throw new Error("❌ Missing app.manifest.json");
18
- }
19
- return { dist, manifest };
20
- }
@@ -1,21 +0,0 @@
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.validateProject = validateProject;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function validateProject(dist, manifest) {
10
- const index = path_1.default.join(dist, "index.html");
11
- if (!fs_1.default.existsSync(dist)) {
12
- throw new Error("❌ dist folder not found");
13
- }
14
- if (!fs_1.default.existsSync(index)) {
15
- throw new Error("❌ dist/index.html missing (not a web build)");
16
- }
17
- if (!manifest.appId || !manifest.appName) {
18
- throw new Error("❌ Invalid manifest (missing appId/appName)");
19
- }
20
- console.log("✔ Project validation OK");
21
- }
@@ -1,97 +0,0 @@
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.resolveZeroConfig = resolveZeroConfig;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- /**
10
- * MAIN ENTRY
11
- * Tries to auto-detect web build + manifest
12
- */
13
- function resolveZeroConfig() {
14
- const cwd = process.cwd();
15
- const dist = findWebDist(cwd);
16
- const manifest = findManifest(cwd);
17
- if (!dist) {
18
- throw new Error("❌ No valid web dist found (index.html missing)");
19
- }
20
- if (!manifest) {
21
- throw new Error("❌ No manifest found (app.manifest.json or manifest.json)");
22
- }
23
- return {
24
- dist,
25
- manifest,
26
- };
27
- }
28
- /**
29
- * -----------------------------
30
- * WEB DIST DETECTION
31
- * -----------------------------
32
- */
33
- function findWebDist(cwd) {
34
- const candidates = ["dist", "build", "www"];
35
- // 1. local folder scan
36
- for (const c of candidates) {
37
- const p = path_1.default.join(cwd, c);
38
- if (isValidWebDist(p)) {
39
- return p;
40
- }
41
- }
42
- // 2. parent folder scan (IMPORTANT for monorepos)
43
- const parent = findInParentDirs(cwd);
44
- if (parent)
45
- return parent;
46
- return null;
47
- }
48
- /**
49
- * Valid web app check
50
- */
51
- function isValidWebDist(dir) {
52
- return fs_1.default.existsSync(path_1.default.join(dir, "index.html"));
53
- }
54
- /**
55
- * Scan upward in directory tree
56
- */
57
- function findInParentDirs(startDir) {
58
- let dir = startDir;
59
- while (dir !== path_1.default.parse(dir).root) {
60
- const candidates = ["dist", "build", "www"];
61
- for (const c of candidates) {
62
- const p = path_1.default.join(dir, c);
63
- if (isValidWebDist(p)) {
64
- return p;
65
- }
66
- }
67
- dir = path_1.default.dirname(dir);
68
- }
69
- return null;
70
- }
71
- /**
72
- * -----------------------------
73
- * MANIFEST DETECTION
74
- * -----------------------------
75
- */
76
- function findManifest(cwd) {
77
- const candidates = ["app.manifest.json", "manifest.json"];
78
- // local scan
79
- for (const c of candidates) {
80
- const p = path_1.default.join(cwd, c);
81
- if (fs_1.default.existsSync(p)) {
82
- return p;
83
- }
84
- }
85
- // parent scan (monorepo support)
86
- let dir = cwd;
87
- while (dir !== path_1.default.parse(dir).root) {
88
- for (const c of candidates) {
89
- const p = path_1.default.join(dir, c);
90
- if (fs_1.default.existsSync(p)) {
91
- return p;
92
- }
93
- }
94
- dir = path_1.default.dirname(dir);
95
- }
96
- return null;
97
- }