preflightlaunch 0.2.2 → 0.2.4
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.
|
@@ -17431,8 +17431,8 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
17431
17431
|
var source_default = chalk;
|
|
17432
17432
|
|
|
17433
17433
|
// src/commands/submit.ts
|
|
17434
|
-
import { readFileSync, statSync as statSync3 } from "fs";
|
|
17435
|
-
import { basename as basename3, resolve as resolve3 } from "path";
|
|
17434
|
+
import { readFileSync, statSync as statSync3, existsSync as existsSync3, readdirSync as readdirSync3 } from "fs";
|
|
17435
|
+
import { basename as basename3, resolve as resolve3, extname as extname2, join as join3 } from "path";
|
|
17436
17436
|
|
|
17437
17437
|
// src/lib/scanner.ts
|
|
17438
17438
|
init_esm_shims();
|
|
@@ -21618,8 +21618,8 @@ var RealtimeChannel = class _RealtimeChannel {
|
|
|
21618
21618
|
_trigger(type, payload, ref) {
|
|
21619
21619
|
var _a, _b;
|
|
21620
21620
|
const typeLower = type.toLocaleLowerCase();
|
|
21621
|
-
const { close, error: error2, leave, join:
|
|
21622
|
-
const events = [close, error2, leave,
|
|
21621
|
+
const { close, error: error2, leave, join: join4 } = CHANNEL_EVENTS;
|
|
21622
|
+
const events = [close, error2, leave, join4];
|
|
21623
21623
|
if (ref && events.indexOf(typeLower) >= 0 && ref !== this._joinRef()) {
|
|
21624
21624
|
return;
|
|
21625
21625
|
}
|
|
@@ -33813,7 +33813,8 @@ var KNOWN_COMMANDS = [
|
|
|
33813
33813
|
{ name: "report", description: "View analysis report" },
|
|
33814
33814
|
{ name: "history", description: "List past submissions" },
|
|
33815
33815
|
{ name: "setup", description: "Run guided setup" },
|
|
33816
|
-
{ name: "asc", description: "App Store Connect integration" }
|
|
33816
|
+
{ name: "asc", description: "App Store Connect integration" },
|
|
33817
|
+
{ name: "update", description: "Update to the latest version" }
|
|
33817
33818
|
];
|
|
33818
33819
|
function levenshtein(a, b) {
|
|
33819
33820
|
const matrix = [];
|
|
@@ -33945,22 +33946,6 @@ function calculateAgeRating(answers) {
|
|
|
33945
33946
|
return "4+";
|
|
33946
33947
|
}
|
|
33947
33948
|
async function collectAppDetails(projectName, defaults) {
|
|
33948
|
-
if (!defaults) {
|
|
33949
|
-
const skipGate = await select({
|
|
33950
|
-
message: "App Details (you can always add these later on the web)",
|
|
33951
|
-
options: [
|
|
33952
|
-
{ value: "fill", label: "Fill in now", hint: "Name, description, keywords, category" },
|
|
33953
|
-
{ value: "skip", label: "Skip for now", hint: "Just use the project name" }
|
|
33954
|
-
]
|
|
33955
|
-
});
|
|
33956
|
-
if (skipGate === null) return null;
|
|
33957
|
-
if (skipGate === "skip") {
|
|
33958
|
-
return {
|
|
33959
|
-
appName: projectName,
|
|
33960
|
-
signInRequired: false
|
|
33961
|
-
};
|
|
33962
|
-
}
|
|
33963
|
-
}
|
|
33964
33949
|
const defaultName = defaults?.appName || projectName;
|
|
33965
33950
|
const appName = await text({
|
|
33966
33951
|
message: "App Name",
|
|
@@ -34081,12 +34066,7 @@ async function collectAgeRating() {
|
|
|
34081
34066
|
if (hasMatureContent === null) return null;
|
|
34082
34067
|
if (!hasMatureContent) {
|
|
34083
34068
|
const rating = calculateAgeRating(defaultAnswers);
|
|
34084
|
-
log.success(`Age Rating: ${rating}
|
|
34085
|
-
const looksRight = await confirm("Does that look right?", true);
|
|
34086
|
-
if (looksRight === null) return null;
|
|
34087
|
-
if (!looksRight) {
|
|
34088
|
-
return collectAgeRatingDetailed(defaultAnswers);
|
|
34089
|
-
}
|
|
34069
|
+
log.success(`Age Rating: ${rating}`);
|
|
34090
34070
|
return { answers: defaultAnswers, rating };
|
|
34091
34071
|
}
|
|
34092
34072
|
return collectAgeRatingDetailed(defaultAnswers);
|
|
@@ -34450,6 +34430,42 @@ async function submitCommand(path5, options = {}, fromMenu = false) {
|
|
|
34450
34430
|
path: detected.screenshots[i]
|
|
34451
34431
|
});
|
|
34452
34432
|
}
|
|
34433
|
+
if (detected.screenshots.length === 0 && fromMenu) {
|
|
34434
|
+
const screenshotPath = await text({
|
|
34435
|
+
message: "Screenshots folder path (press Enter to skip)",
|
|
34436
|
+
placeholder: "e.g. ~/Desktop/screenshots"
|
|
34437
|
+
});
|
|
34438
|
+
if (screenshotPath === null) {
|
|
34439
|
+
await offerDraftSave(draftState);
|
|
34440
|
+
return;
|
|
34441
|
+
}
|
|
34442
|
+
if (screenshotPath.trim()) {
|
|
34443
|
+
const resolved = resolve3(screenshotPath.trim().replace(/^~/, process.env.HOME || ""));
|
|
34444
|
+
if (existsSync3(resolved)) {
|
|
34445
|
+
const imageExts = [".png", ".jpg", ".jpeg"];
|
|
34446
|
+
try {
|
|
34447
|
+
const files = readdirSync3(resolved).filter((f) => imageExts.includes(extname2(f).toLowerCase())).map((f) => join3(resolved, f));
|
|
34448
|
+
for (let i = 0; i < Math.min(files.length, 10); i++) {
|
|
34449
|
+
filesToUpload.push({
|
|
34450
|
+
type: "screenshot",
|
|
34451
|
+
index: i,
|
|
34452
|
+
filename: basename3(files[i]),
|
|
34453
|
+
path: files[i]
|
|
34454
|
+
});
|
|
34455
|
+
}
|
|
34456
|
+
if (files.length > 0) {
|
|
34457
|
+
log.success(`Found ${files.length} screenshot${files.length === 1 ? "" : "s"}`);
|
|
34458
|
+
} else {
|
|
34459
|
+
log.info("No images found in that folder.");
|
|
34460
|
+
}
|
|
34461
|
+
} catch {
|
|
34462
|
+
log.warning("Could not read that directory.");
|
|
34463
|
+
}
|
|
34464
|
+
} else {
|
|
34465
|
+
log.warning("Folder not found. Continuing without screenshots.");
|
|
34466
|
+
}
|
|
34467
|
+
}
|
|
34468
|
+
}
|
|
34453
34469
|
if (filesToUpload.length === 0) {
|
|
34454
34470
|
log.warning("No files to upload. Make sure you're pointing to an Xcode project directory.");
|
|
34455
34471
|
if (fromMenu) return;
|
|
@@ -34459,42 +34475,29 @@ async function submitCommand(path5, options = {}, fromMenu = false) {
|
|
|
34459
34475
|
let appDetails = null;
|
|
34460
34476
|
let compliance = null;
|
|
34461
34477
|
if (fromMenu) {
|
|
34462
|
-
|
|
34463
|
-
|
|
34464
|
-
|
|
34465
|
-
{ value: "quick", label: "Quick review (just analyze my project files)", hint: "Fastest option" },
|
|
34466
|
-
{ value: "full", label: "Full review (add app details + compliance info)", hint: "More thorough" }
|
|
34467
|
-
]
|
|
34468
|
-
});
|
|
34469
|
-
if (reviewType === null) {
|
|
34470
|
-
if (fromMenu) await offerDraftSave(draftState);
|
|
34478
|
+
appDetails = await collectAppDetails(projectName);
|
|
34479
|
+
if (appDetails === null) {
|
|
34480
|
+
await offerDraftSave(draftState);
|
|
34471
34481
|
return;
|
|
34472
34482
|
}
|
|
34473
|
-
|
|
34474
|
-
|
|
34475
|
-
|
|
34476
|
-
|
|
34477
|
-
|
|
34478
|
-
|
|
34479
|
-
|
|
34480
|
-
|
|
34481
|
-
|
|
34482
|
-
|
|
34483
|
-
|
|
34484
|
-
|
|
34485
|
-
|
|
34486
|
-
|
|
34487
|
-
draftState
|
|
34488
|
-
|
|
34489
|
-
draftState.demoPassword = appDetails.demoPassword;
|
|
34490
|
-
appDetails = await offerAscAutofill(appDetails);
|
|
34491
|
-
compliance = await collectCompliance();
|
|
34492
|
-
if (compliance === null) {
|
|
34493
|
-
if (fromMenu) await offerDraftSave(draftState);
|
|
34494
|
-
return;
|
|
34495
|
-
}
|
|
34496
|
-
draftState.compliance = compliance;
|
|
34483
|
+
appName = appDetails.appName;
|
|
34484
|
+
draftState.appName = appName;
|
|
34485
|
+
draftState.description = appDetails.description;
|
|
34486
|
+
draftState.keywords = appDetails.keywords;
|
|
34487
|
+
draftState.category = appDetails.category;
|
|
34488
|
+
draftState.supportUrl = appDetails.supportUrl;
|
|
34489
|
+
draftState.promotionalText = appDetails.promotionalText;
|
|
34490
|
+
draftState.marketingUrl = appDetails.marketingUrl;
|
|
34491
|
+
draftState.signInRequired = appDetails.signInRequired;
|
|
34492
|
+
draftState.demoUsername = appDetails.demoUsername;
|
|
34493
|
+
draftState.demoPassword = appDetails.demoPassword;
|
|
34494
|
+
appDetails = await offerAscAutofill(appDetails);
|
|
34495
|
+
compliance = await collectCompliance();
|
|
34496
|
+
if (compliance === null) {
|
|
34497
|
+
await offerDraftSave(draftState);
|
|
34498
|
+
return;
|
|
34497
34499
|
}
|
|
34500
|
+
draftState.compliance = compliance;
|
|
34498
34501
|
}
|
|
34499
34502
|
if (fromMenu) {
|
|
34500
34503
|
console.log();
|
|
@@ -34990,4 +34993,4 @@ export {
|
|
|
34990
34993
|
submitCommand,
|
|
34991
34994
|
resumeSubmitCommand
|
|
34992
34995
|
};
|
|
34993
|
-
//# sourceMappingURL=chunk-
|
|
34996
|
+
//# sourceMappingURL=chunk-5WAPKABO.js.map
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
text,
|
|
40
40
|
tip,
|
|
41
41
|
warning
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-5WAPKABO.js";
|
|
43
43
|
import {
|
|
44
44
|
__commonJS,
|
|
45
45
|
__require,
|
|
@@ -5389,7 +5389,7 @@ async function scanCommand(path) {
|
|
|
5389
5389
|
]
|
|
5390
5390
|
});
|
|
5391
5391
|
if (next === "submit") {
|
|
5392
|
-
const { submitCommand: submitCommand2 } = await import("./submit-
|
|
5392
|
+
const { submitCommand: submitCommand2 } = await import("./submit-BWB7XOAF.js");
|
|
5393
5393
|
await submitCommand2(dir, {});
|
|
5394
5394
|
} else {
|
|
5395
5395
|
tip(`Run ${brand("preflight submit")} anytime to get AI-powered fix instructions.`);
|
|
@@ -5897,6 +5897,45 @@ async function ascStatusCommand() {
|
|
|
5897
5897
|
log.error(`Error: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
5898
5898
|
}
|
|
5899
5899
|
}
|
|
5900
|
+
async function ascRefreshCommand() {
|
|
5901
|
+
const s = spinner();
|
|
5902
|
+
s.start("Checking App Store Connect...");
|
|
5903
|
+
try {
|
|
5904
|
+
const statusRes = await apiRequest("/api/asc/connect");
|
|
5905
|
+
const statusData = await statusRes.json();
|
|
5906
|
+
if (!statusRes.ok || !statusData.connected) {
|
|
5907
|
+
s.stop("Not connected");
|
|
5908
|
+
log.warning("App Store Connect is not connected.");
|
|
5909
|
+
console.log(subtext(` Run ${brand("preflight asc connect")} to set up.`));
|
|
5910
|
+
console.log();
|
|
5911
|
+
return;
|
|
5912
|
+
}
|
|
5913
|
+
s.message = "Pulling latest data from App Store Connect...";
|
|
5914
|
+
const res = await apiRequest("/api/asc/autofill", {
|
|
5915
|
+
method: "POST",
|
|
5916
|
+
body: JSON.stringify({ appId: statusData.appId })
|
|
5917
|
+
});
|
|
5918
|
+
const data = await res.json();
|
|
5919
|
+
if (!res.ok) {
|
|
5920
|
+
s.stop("Refresh failed");
|
|
5921
|
+
log.error(data.message || "Could not refresh data from App Store Connect");
|
|
5922
|
+
return;
|
|
5923
|
+
}
|
|
5924
|
+
s.stop("Data refreshed!");
|
|
5925
|
+
console.log();
|
|
5926
|
+
if (data.app_name) console.log(` App: ${brand(data.app_name)}`);
|
|
5927
|
+
if (data.description) console.log(` Description: ${subtext(data.description.slice(0, 60) + (data.description.length > 60 ? "..." : ""))}`);
|
|
5928
|
+
if (data.keywords) console.log(` Keywords: ${subtext(data.keywords.slice(0, 60) + (data.keywords.length > 60 ? "..." : ""))}`);
|
|
5929
|
+
if (data.category) console.log(` Category: ${subtext(data.category)}`);
|
|
5930
|
+
if (data.support_url) console.log(` Support URL: ${subtext(data.support_url)}`);
|
|
5931
|
+
console.log();
|
|
5932
|
+
log.success("This data will autofill your next submission.");
|
|
5933
|
+
console.log();
|
|
5934
|
+
} catch (err) {
|
|
5935
|
+
s.stop("Refresh failed");
|
|
5936
|
+
log.error(`Error: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
5937
|
+
}
|
|
5938
|
+
}
|
|
5900
5939
|
async function ascDisconnectCommand() {
|
|
5901
5940
|
const confirmed = await confirm("Disconnect from App Store Connect?", false);
|
|
5902
5941
|
if (confirmed === null || !confirmed) return;
|
|
@@ -5925,6 +5964,7 @@ async function ascInteractiveMenu() {
|
|
|
5925
5964
|
message: "App Store Connect",
|
|
5926
5965
|
options: [
|
|
5927
5966
|
{ value: "connect", label: "Connect", hint: "Set up API key" },
|
|
5967
|
+
{ value: "refresh", label: "Refresh", hint: "Pull latest data from ASC" },
|
|
5928
5968
|
{ value: "status", label: "View Status", hint: "Check connection" },
|
|
5929
5969
|
{ value: "disconnect", label: "Disconnect", hint: "Remove API key" },
|
|
5930
5970
|
{ value: "back", label: "Back to menu" }
|
|
@@ -5935,6 +5975,9 @@ async function ascInteractiveMenu() {
|
|
|
5935
5975
|
case "connect":
|
|
5936
5976
|
await ascConnectCommand();
|
|
5937
5977
|
break;
|
|
5978
|
+
case "refresh":
|
|
5979
|
+
await ascRefreshCommand();
|
|
5980
|
+
break;
|
|
5938
5981
|
case "status":
|
|
5939
5982
|
await ascStatusCommand();
|
|
5940
5983
|
break;
|
|
@@ -5945,9 +5988,84 @@ async function ascInteractiveMenu() {
|
|
|
5945
5988
|
}
|
|
5946
5989
|
}
|
|
5947
5990
|
|
|
5991
|
+
// src/commands/update.ts
|
|
5992
|
+
init_esm_shims();
|
|
5993
|
+
import { execFileSync } from "child_process";
|
|
5994
|
+
import { createRequire } from "module";
|
|
5995
|
+
function getCurrentVersion() {
|
|
5996
|
+
const require2 = createRequire(import.meta.url);
|
|
5997
|
+
const pkg = require2("../../package.json");
|
|
5998
|
+
return pkg.version;
|
|
5999
|
+
}
|
|
6000
|
+
async function getLatestVersion() {
|
|
6001
|
+
try {
|
|
6002
|
+
const res = await fetch("https://registry.npmjs.org/preflightlaunch/latest");
|
|
6003
|
+
if (!res.ok) return null;
|
|
6004
|
+
const data = await res.json();
|
|
6005
|
+
return data.version ?? null;
|
|
6006
|
+
} catch {
|
|
6007
|
+
return null;
|
|
6008
|
+
}
|
|
6009
|
+
}
|
|
6010
|
+
function compareSemver(a, b) {
|
|
6011
|
+
const pa = a.split(".").map(Number);
|
|
6012
|
+
const pb = b.split(".").map(Number);
|
|
6013
|
+
for (let i = 0; i < 3; i++) {
|
|
6014
|
+
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return -1;
|
|
6015
|
+
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return 1;
|
|
6016
|
+
}
|
|
6017
|
+
return 0;
|
|
6018
|
+
}
|
|
6019
|
+
async function updateCommand() {
|
|
6020
|
+
const current = getCurrentVersion();
|
|
6021
|
+
const s = spinner();
|
|
6022
|
+
s.start("Checking for updates...");
|
|
6023
|
+
const latest = await getLatestVersion();
|
|
6024
|
+
if (!latest) {
|
|
6025
|
+
s.stop("Could not check for updates");
|
|
6026
|
+
log.error("Failed to reach npm registry. Check your internet connection.");
|
|
6027
|
+
return;
|
|
6028
|
+
}
|
|
6029
|
+
if (compareSemver(current, latest) >= 0) {
|
|
6030
|
+
s.stop("Up to date!");
|
|
6031
|
+
console.log();
|
|
6032
|
+
console.log(` ${brand("Preflight")} ${brandDim(`v${current}`)} is the latest version.`);
|
|
6033
|
+
console.log();
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
s.stop(`Update available: ${current} \u2192 ${latest}`);
|
|
6037
|
+
console.log();
|
|
6038
|
+
const installSpinner = spinner();
|
|
6039
|
+
installSpinner.start(`Installing v${latest}...`);
|
|
6040
|
+
try {
|
|
6041
|
+
execFileSync("npm", ["install", "-g", "preflightlaunch@latest"], {
|
|
6042
|
+
stdio: "pipe",
|
|
6043
|
+
timeout: 6e4
|
|
6044
|
+
});
|
|
6045
|
+
installSpinner.stop(`Updated to v${latest}!`);
|
|
6046
|
+
console.log();
|
|
6047
|
+
console.log(` ${brand("Preflight")} has been updated to ${brandDim(`v${latest}`)}.`);
|
|
6048
|
+
console.log();
|
|
6049
|
+
} catch (err) {
|
|
6050
|
+
installSpinner.stop("Update failed");
|
|
6051
|
+
const msg = err instanceof Error ? err.message : "";
|
|
6052
|
+
if (msg.includes("EACCES") || msg.includes("permission")) {
|
|
6053
|
+
console.log();
|
|
6054
|
+
log.warning("Permission denied. Try running with sudo:");
|
|
6055
|
+
console.log(subtext(` sudo npm install -g preflightlaunch@latest`));
|
|
6056
|
+
console.log();
|
|
6057
|
+
} else {
|
|
6058
|
+
console.log();
|
|
6059
|
+
log.error("Could not update automatically. Run manually:");
|
|
6060
|
+
console.log(subtext(` npm install -g preflightlaunch@latest`));
|
|
6061
|
+
console.log();
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
}
|
|
6065
|
+
|
|
5948
6066
|
// src/index.ts
|
|
5949
6067
|
var program2 = new Command();
|
|
5950
|
-
program2.name("preflight").description("Preflight - App Store Review Scanner").version("0.2.
|
|
6068
|
+
program2.name("preflight").description("Preflight - App Store Review Scanner").version("0.2.4");
|
|
5951
6069
|
program2.command("login").description("Log in to Preflight (opens browser)").action(loginCommand);
|
|
5952
6070
|
program2.command("logout").description("Log out and clear stored credentials").action(logoutCommand);
|
|
5953
6071
|
program2.command("whoami").description("Show current user and credit balance").action(whoamiCommand);
|
|
@@ -5958,9 +6076,11 @@ program2.command("report [id]").description("View full analysis report").option(
|
|
|
5958
6076
|
program2.command("history").description("List past submissions").option("--json", "Output as JSON").action(historyCommand);
|
|
5959
6077
|
program2.command("credits").description("Show credit balance").action(creditsCommand);
|
|
5960
6078
|
program2.command("setup").description("Run guided setup (can be re-run anytime)").action(setupCommand);
|
|
6079
|
+
program2.command("update").description("Update Preflight to the latest version").action(updateCommand);
|
|
5961
6080
|
var ascCmd = program2.command("asc").description("App Store Connect integration");
|
|
5962
6081
|
ascCmd.command("connect").description("Connect your App Store Connect account").action(ascConnectCommand);
|
|
5963
6082
|
ascCmd.command("status").description("Check App Store Connect connection status").action(ascStatusCommand);
|
|
6083
|
+
ascCmd.command("refresh").description("Pull latest metadata from App Store Connect").action(ascRefreshCommand);
|
|
5964
6084
|
ascCmd.command("disconnect").description("Disconnect from App Store Connect").action(ascDisconnectCommand);
|
|
5965
6085
|
program2.on("command:*", (operands) => {
|
|
5966
6086
|
handleUnknownCommand(operands[0]);
|
|
@@ -4,10 +4,10 @@ const require = createRequire(import.meta.url);
|
|
|
4
4
|
import {
|
|
5
5
|
resumeSubmitCommand,
|
|
6
6
|
submitCommand
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5WAPKABO.js";
|
|
8
8
|
import "./chunk-45JYNMSU.js";
|
|
9
9
|
export {
|
|
10
10
|
resumeSubmitCommand,
|
|
11
11
|
submitCommand
|
|
12
12
|
};
|
|
13
|
-
//# sourceMappingURL=submit-
|
|
13
|
+
//# sourceMappingURL=submit-BWB7XOAF.js.map
|