percher 0.5.17 → 0.5.19
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/bin/percher.js +208 -70
- package/dist/package.json +4 -4
- package/package.json +4 -4
package/dist/bin/percher.js
CHANGED
|
@@ -106338,6 +106338,9 @@ class AppsResource {
|
|
|
106338
106338
|
importFromGithub(appRef, input) {
|
|
106339
106339
|
return this.http.post(`/apps/${encodeURIComponent(appRef)}/import/github`, input);
|
|
106340
106340
|
}
|
|
106341
|
+
importGithub(input) {
|
|
106342
|
+
return this.http.post("/apps/import-github", input);
|
|
106343
|
+
}
|
|
106341
106344
|
setupWebhook(appRef) {
|
|
106342
106345
|
return this.http.post(`/apps/${encodeURIComponent(appRef)}/webhook/setup`, {});
|
|
106343
106346
|
}
|
|
@@ -108052,6 +108055,7 @@ function buildTarball(fileBuffers) {
|
|
|
108052
108055
|
fileCount: fileBuffers.length,
|
|
108053
108056
|
topFiles,
|
|
108054
108057
|
topEntries,
|
|
108058
|
+
topLevelEntries: [...entrySizes.keys()],
|
|
108055
108059
|
contentHash
|
|
108056
108060
|
};
|
|
108057
108061
|
}
|
|
@@ -110236,6 +110240,89 @@ function configFromDetection(name, detected, dataMode) {
|
|
|
110236
110240
|
};
|
|
110237
110241
|
}
|
|
110238
110242
|
|
|
110243
|
+
// ../core/dist/validation/blocked-names.js
|
|
110244
|
+
var BLOCKED_APP_NAMES = new Set([
|
|
110245
|
+
"api",
|
|
110246
|
+
"app",
|
|
110247
|
+
"admin",
|
|
110248
|
+
"dashboard",
|
|
110249
|
+
"www",
|
|
110250
|
+
"mail",
|
|
110251
|
+
"smtp",
|
|
110252
|
+
"ftp",
|
|
110253
|
+
"ssh",
|
|
110254
|
+
"root",
|
|
110255
|
+
"system",
|
|
110256
|
+
"internal",
|
|
110257
|
+
"auth",
|
|
110258
|
+
"oauth",
|
|
110259
|
+
"billing",
|
|
110260
|
+
"help",
|
|
110261
|
+
"status",
|
|
110262
|
+
"cdn",
|
|
110263
|
+
"assets",
|
|
110264
|
+
"static",
|
|
110265
|
+
"pb",
|
|
110266
|
+
"pocketbase",
|
|
110267
|
+
"forgejo",
|
|
110268
|
+
"caddy",
|
|
110269
|
+
"git",
|
|
110270
|
+
"percher",
|
|
110271
|
+
"mcp",
|
|
110272
|
+
"preview",
|
|
110273
|
+
"metrics",
|
|
110274
|
+
"login",
|
|
110275
|
+
"signin",
|
|
110276
|
+
"signup",
|
|
110277
|
+
"register",
|
|
110278
|
+
"account",
|
|
110279
|
+
"paypal",
|
|
110280
|
+
"stripe",
|
|
110281
|
+
"bank",
|
|
110282
|
+
"apple",
|
|
110283
|
+
"microsoft",
|
|
110284
|
+
"google",
|
|
110285
|
+
"amazon",
|
|
110286
|
+
"facebook",
|
|
110287
|
+
"meta",
|
|
110288
|
+
"instagram",
|
|
110289
|
+
"twitter",
|
|
110290
|
+
"tiktok",
|
|
110291
|
+
"netflix",
|
|
110292
|
+
"spotify",
|
|
110293
|
+
"support",
|
|
110294
|
+
"security",
|
|
110295
|
+
"verify",
|
|
110296
|
+
"update",
|
|
110297
|
+
"confirm",
|
|
110298
|
+
"recovery"
|
|
110299
|
+
]);
|
|
110300
|
+
function isBlockedName(name) {
|
|
110301
|
+
if (BLOCKED_APP_NAMES.has(name))
|
|
110302
|
+
return true;
|
|
110303
|
+
const prefixes = [
|
|
110304
|
+
"login-",
|
|
110305
|
+
"signin-",
|
|
110306
|
+
"signup-",
|
|
110307
|
+
"paypal-",
|
|
110308
|
+
"bank-",
|
|
110309
|
+
"apple-",
|
|
110310
|
+
"microsoft-",
|
|
110311
|
+
"google-",
|
|
110312
|
+
"amazon-",
|
|
110313
|
+
"support-",
|
|
110314
|
+
"admin-",
|
|
110315
|
+
"pb-",
|
|
110316
|
+
"percher-",
|
|
110317
|
+
"security-",
|
|
110318
|
+
"verify-",
|
|
110319
|
+
"update-",
|
|
110320
|
+
"confirm-",
|
|
110321
|
+
"recovery-"
|
|
110322
|
+
];
|
|
110323
|
+
return prefixes.some((p) => name.startsWith(p));
|
|
110324
|
+
}
|
|
110325
|
+
|
|
110239
110326
|
// ../core/dist/commands/init.js
|
|
110240
110327
|
function isSuspiciousAutoName(name) {
|
|
110241
110328
|
if (/-\d{8,}$/.test(name))
|
|
@@ -110246,6 +110333,12 @@ function isSuspiciousAutoName(name) {
|
|
|
110246
110333
|
return true;
|
|
110247
110334
|
return false;
|
|
110248
110335
|
}
|
|
110336
|
+
function adjustReservedName(name) {
|
|
110337
|
+
let adjusted = `app-${name}`;
|
|
110338
|
+
if (adjusted.length > 40)
|
|
110339
|
+
adjusted = adjusted.slice(0, 40).replace(/-+$/g, "");
|
|
110340
|
+
return adjusted;
|
|
110341
|
+
}
|
|
110249
110342
|
function detectInteractive() {
|
|
110250
110343
|
return process.stdin?.isTTY === true && process.stdout?.isTTY === true;
|
|
110251
110344
|
}
|
|
@@ -110273,16 +110366,24 @@ async function init(ctx, input = {}) {
|
|
|
110273
110366
|
if (input.name) {
|
|
110274
110367
|
name = input.name;
|
|
110275
110368
|
} else {
|
|
110276
|
-
|
|
110369
|
+
let suggestion = generateName(basename3(ctx.cwd));
|
|
110370
|
+
const reserved = isBlockedName(suggestion);
|
|
110371
|
+
if (reserved)
|
|
110372
|
+
suggestion = adjustReservedName(suggestion);
|
|
110277
110373
|
const interactive = input.interactive ?? detectInteractive();
|
|
110278
|
-
|
|
110279
|
-
|
|
110374
|
+
const flagged = reserved || isSuspiciousAutoName(suggestion);
|
|
110375
|
+
if (flagged && interactive) {
|
|
110376
|
+
const lead = reserved ? `'${basename3(ctx.cwd)}' maps to a reserved app name; suggested '${suggestion}'` : `Suggested app name: '${suggestion}'`;
|
|
110377
|
+
const answer = (await ctx.prompt(`${lead}. Press Enter to accept, or type a different name: `, {
|
|
110378
|
+
default: suggestion
|
|
110379
|
+
})).trim();
|
|
110280
110380
|
name = answer.length > 0 ? answer : suggestion;
|
|
110281
110381
|
} else {
|
|
110282
|
-
if (
|
|
110382
|
+
if (flagged) {
|
|
110383
|
+
const reason = reserved ? `auto-generated app name was reserved — using '${suggestion}'.` : `auto-generated app name '${suggestion}' looks like a temp-dir slug.`;
|
|
110283
110384
|
const writer = ctx.stderr.getWriter();
|
|
110284
110385
|
try {
|
|
110285
|
-
await writer.write(new TextEncoder().encode(`warning:
|
|
110386
|
+
await writer.write(new TextEncoder().encode(`warning: ${reason} Set [app].name in percher.toml or pass --name to override.
|
|
110286
110387
|
`));
|
|
110287
110388
|
} finally {
|
|
110288
110389
|
writer.releaseLock();
|
|
@@ -114372,6 +114473,74 @@ function solvePow(nonce, difficulty, maxIterations = 50000000) {
|
|
|
114372
114473
|
return null;
|
|
114373
114474
|
}
|
|
114374
114475
|
|
|
114476
|
+
// ../core/dist/bundle-completeness.js
|
|
114477
|
+
var import_cross_spawn2 = __toESM(require_cross_spawn(), 1);
|
|
114478
|
+
var ARTIFACT_DIRS = new Set([
|
|
114479
|
+
"node_modules",
|
|
114480
|
+
".git",
|
|
114481
|
+
"dist",
|
|
114482
|
+
"build",
|
|
114483
|
+
".next",
|
|
114484
|
+
".svelte-kit",
|
|
114485
|
+
"coverage",
|
|
114486
|
+
".bun",
|
|
114487
|
+
"out",
|
|
114488
|
+
".turbo",
|
|
114489
|
+
".cache",
|
|
114490
|
+
".vercel",
|
|
114491
|
+
".netlify"
|
|
114492
|
+
]);
|
|
114493
|
+
var ASSET_DIRS = new Set(["public", "static", "assets"]);
|
|
114494
|
+
var SEVERE_SHRINK_PCT = 60;
|
|
114495
|
+
function gitTrackedFiles(cwd) {
|
|
114496
|
+
try {
|
|
114497
|
+
const res = import_cross_spawn2.default.sync("git", ["ls-files", "-z"], { cwd, encoding: "utf8" });
|
|
114498
|
+
if (res.status !== 0 || typeof res.stdout !== "string")
|
|
114499
|
+
return null;
|
|
114500
|
+
const files = res.stdout.split("\x00").filter(Boolean);
|
|
114501
|
+
return files.length > 0 ? files : null;
|
|
114502
|
+
} catch {
|
|
114503
|
+
return null;
|
|
114504
|
+
}
|
|
114505
|
+
}
|
|
114506
|
+
function checkBundleCompleteness(opts) {
|
|
114507
|
+
const tracked = gitTrackedFiles(opts.cwd);
|
|
114508
|
+
if (!tracked)
|
|
114509
|
+
return null;
|
|
114510
|
+
const packedDirs = new Set(opts.topLevelEntries.filter((e) => e.endsWith("/")).map((e) => e.slice(0, -1)));
|
|
114511
|
+
const trackedDirs = new Set;
|
|
114512
|
+
for (const f of tracked) {
|
|
114513
|
+
const slash = f.indexOf("/");
|
|
114514
|
+
if (slash === -1)
|
|
114515
|
+
continue;
|
|
114516
|
+
const top = f.slice(0, slash);
|
|
114517
|
+
if (!ARTIFACT_DIRS.has(top))
|
|
114518
|
+
trackedDirs.add(top);
|
|
114519
|
+
}
|
|
114520
|
+
const excludedDirs = [...trackedDirs].filter((d) => !packedDirs.has(d)).sort();
|
|
114521
|
+
if (excludedDirs.length === 0)
|
|
114522
|
+
return null;
|
|
114523
|
+
const shrinkPct = Math.round((1 - opts.packedFileCount / tracked.length) * 100);
|
|
114524
|
+
const isStatic = opts.config.app.runtime === "static";
|
|
114525
|
+
const assetExcluded = excludedDirs.some((d) => ASSET_DIRS.has(d));
|
|
114526
|
+
let reason = null;
|
|
114527
|
+
if (assetExcluded)
|
|
114528
|
+
reason = "asset_dir_excluded";
|
|
114529
|
+
else if (isStatic)
|
|
114530
|
+
reason = "static_content_excluded";
|
|
114531
|
+
else if (shrinkPct >= SEVERE_SHRINK_PCT)
|
|
114532
|
+
reason = "severe_shrink";
|
|
114533
|
+
if (!reason)
|
|
114534
|
+
return null;
|
|
114535
|
+
return { excludedDirs, shrinkPct, reason };
|
|
114536
|
+
}
|
|
114537
|
+
function bundleCompletenessMessage(w, config2) {
|
|
114538
|
+
const label = config2.app.framework ? `${config2.app.framework} (${config2.app.runtime})` : config2.app.runtime;
|
|
114539
|
+
const dirs = w.excludedDirs.map((d) => `${d}/`).join(", ");
|
|
114540
|
+
const assetNote = w.reason === "asset_dir_excluded" ? " Those hold static assets — the deployed app will be missing them." : w.reason === "static_content_excluded" ? " A static app serves exactly these files, so the deployed site will be missing content." : "";
|
|
114541
|
+
return `Detected a ${label} app, but the upload is missing ${w.excludedDirs.length} git-tracked ` + `director${w.excludedDirs.length === 1 ? "y" : "ies"} (${dirs}) — the bundle has ~${w.shrinkPct}% ` + `fewer files than your repo tracks.${assetNote} This is almost always an over-broad ` + `.gitignore/.percherignore rule. Those are gitignore-style patterns: a bare \`name\` matches a ` + `\`name/\` directory at ANY depth, so anchor to the repo root with a leading slash (e.g. \`/build\`) ` + `when you mean only the top-level one. If the exclusion is intentional, re-run with --force.`;
|
|
114542
|
+
}
|
|
114543
|
+
|
|
114375
114544
|
// ../core/dist/event-renderer.js
|
|
114376
114545
|
function renderDeployEvent(event) {
|
|
114377
114546
|
if (event.stage === "queue") {
|
|
@@ -115387,7 +115556,7 @@ ${bullets}`,
|
|
|
115387
115556
|
error: {
|
|
115388
115557
|
title: "Repository too large",
|
|
115389
115558
|
explanation: `The project is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, which exceeds the 500 MB limit.`,
|
|
115390
|
-
suggestion: `Add large files/folders to .gitignore or .percherignore. Biggest: ${formatBiggestEntries(tarball.topEntries)}`
|
|
115559
|
+
suggestion: `Add large files/folders to .gitignore or .percherignore (gitignore-style — anchor with a leading / for top-level only, e.g. /assets). Biggest: ${formatBiggestEntries(tarball.topEntries)}`
|
|
115391
115560
|
},
|
|
115392
115561
|
recovery: recoveryAsk({
|
|
115393
115562
|
prompt: `Repository is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, which exceeds the 500 MB upload limit. Add large files/folders to .gitignore or .percherignore (biggest: ${formatBiggestEntries(tarball.topEntries)}) and try again.`,
|
|
@@ -115399,7 +115568,33 @@ ${bullets}`,
|
|
|
115399
115568
|
};
|
|
115400
115569
|
}
|
|
115401
115570
|
if (!input.force && (tarball.fileCount > SUSPICIOUS_FILES || tarball.bytes > SUSPICIOUS_BYTES)) {
|
|
115402
|
-
ctx.status(`Warning: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB — auto-continuing (MCP mode). Biggest: ${formatBiggestEntries(tarball.topEntries)}. Trim the upload by adding large items to .gitignore or .percherignore.`);
|
|
115571
|
+
ctx.status(`Warning: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB — auto-continuing (MCP mode). Biggest: ${formatBiggestEntries(tarball.topEntries)}. Trim the upload by adding large items to .gitignore or .percherignore (gitignore-style patterns — anchor with a leading / for top-level only, e.g. /assets).`);
|
|
115572
|
+
}
|
|
115573
|
+
if (!input.force) {
|
|
115574
|
+
const completeness = checkBundleCompleteness({
|
|
115575
|
+
cwd: ctx.cwd,
|
|
115576
|
+
config: config2,
|
|
115577
|
+
topLevelEntries: tarball.topLevelEntries,
|
|
115578
|
+
packedFileCount: tarball.fileCount
|
|
115579
|
+
});
|
|
115580
|
+
if (completeness) {
|
|
115581
|
+
const message = bundleCompletenessMessage(completeness, config2);
|
|
115582
|
+
const excluded = completeness.excludedDirs.map((d) => `${d}/`).join(", ");
|
|
115583
|
+
return {
|
|
115584
|
+
status: "failed",
|
|
115585
|
+
fileCount: tarball.fileCount,
|
|
115586
|
+
bytes: tarball.bytes,
|
|
115587
|
+
error: {
|
|
115588
|
+
title: "Bundle is missing git-tracked files",
|
|
115589
|
+
explanation: message,
|
|
115590
|
+
suggestion: "Fix the .gitignore/.percherignore pattern that excluded it, or re-run with --force if intentional."
|
|
115591
|
+
},
|
|
115592
|
+
recovery: recoveryAsk({ prompt: message, reasonCode: "unknown" }),
|
|
115593
|
+
summary: `Upload is missing git-tracked dir(s): ${excluded} (~${completeness.shrinkPct}% fewer files than tracked). Re-run with --force if intentional.`,
|
|
115594
|
+
configPath: tomlPathFor2(ctx.cwd),
|
|
115595
|
+
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
115596
|
+
};
|
|
115597
|
+
}
|
|
115403
115598
|
}
|
|
115404
115599
|
emitPreflight(ctx, config2, {
|
|
115405
115600
|
fileCount: tarball.fileCount,
|
|
@@ -116653,10 +116848,10 @@ function updateLocalTomlName(cwd, oldName, newName) {
|
|
|
116653
116848
|
import { mkdtempSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
116654
116849
|
import { tmpdir } from "node:os";
|
|
116655
116850
|
import { join as join27 } from "node:path";
|
|
116656
|
-
var
|
|
116851
|
+
var import_cross_spawn3 = __toESM(require_cross_spawn(), 1);
|
|
116657
116852
|
function runProcessExit(cmd, args, opts = {}) {
|
|
116658
116853
|
return new Promise((resolve11, reject) => {
|
|
116659
|
-
const child =
|
|
116854
|
+
const child = import_cross_spawn3.default(cmd, args, {
|
|
116660
116855
|
cwd: opts.cwd,
|
|
116661
116856
|
stdio: opts.inherit ? "inherit" : "ignore"
|
|
116662
116857
|
});
|
|
@@ -117372,63 +117567,6 @@ var PLAN_IDS = Object.entries(PLAN_CATALOG).filter(([, info]) => !info.hidden).m
|
|
|
117372
117567
|
// ../core/dist/index.js
|
|
117373
117568
|
init_qr();
|
|
117374
117569
|
|
|
117375
|
-
// ../core/dist/validation/blocked-names.js
|
|
117376
|
-
var BLOCKED_APP_NAMES = new Set([
|
|
117377
|
-
"api",
|
|
117378
|
-
"app",
|
|
117379
|
-
"admin",
|
|
117380
|
-
"dashboard",
|
|
117381
|
-
"www",
|
|
117382
|
-
"mail",
|
|
117383
|
-
"smtp",
|
|
117384
|
-
"ftp",
|
|
117385
|
-
"ssh",
|
|
117386
|
-
"root",
|
|
117387
|
-
"system",
|
|
117388
|
-
"internal",
|
|
117389
|
-
"auth",
|
|
117390
|
-
"oauth",
|
|
117391
|
-
"billing",
|
|
117392
|
-
"help",
|
|
117393
|
-
"status",
|
|
117394
|
-
"cdn",
|
|
117395
|
-
"assets",
|
|
117396
|
-
"static",
|
|
117397
|
-
"pb",
|
|
117398
|
-
"pocketbase",
|
|
117399
|
-
"forgejo",
|
|
117400
|
-
"caddy",
|
|
117401
|
-
"git",
|
|
117402
|
-
"percher",
|
|
117403
|
-
"mcp",
|
|
117404
|
-
"preview",
|
|
117405
|
-
"metrics",
|
|
117406
|
-
"login",
|
|
117407
|
-
"signin",
|
|
117408
|
-
"signup",
|
|
117409
|
-
"register",
|
|
117410
|
-
"account",
|
|
117411
|
-
"paypal",
|
|
117412
|
-
"stripe",
|
|
117413
|
-
"bank",
|
|
117414
|
-
"apple",
|
|
117415
|
-
"microsoft",
|
|
117416
|
-
"google",
|
|
117417
|
-
"amazon",
|
|
117418
|
-
"facebook",
|
|
117419
|
-
"meta",
|
|
117420
|
-
"instagram",
|
|
117421
|
-
"twitter",
|
|
117422
|
-
"tiktok",
|
|
117423
|
-
"netflix",
|
|
117424
|
-
"spotify",
|
|
117425
|
-
"support",
|
|
117426
|
-
"security",
|
|
117427
|
-
"verify",
|
|
117428
|
-
"update",
|
|
117429
|
-
"confirm",
|
|
117430
|
-
"recovery"
|
|
117431
|
-
]);
|
|
117432
117570
|
// src/cli-utils.ts
|
|
117433
117571
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
117434
117572
|
|
|
@@ -119504,7 +119642,7 @@ async function renderError(stderr, error48) {
|
|
|
119504
119642
|
// package.json
|
|
119505
119643
|
var package_default = {
|
|
119506
119644
|
name: "percher",
|
|
119507
|
-
version: "0.5.
|
|
119645
|
+
version: "0.5.19",
|
|
119508
119646
|
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
119509
119647
|
type: "module",
|
|
119510
119648
|
bin: {
|
|
@@ -119528,9 +119666,9 @@ var package_default = {
|
|
|
119528
119666
|
typecheck: "tsc --noEmit"
|
|
119529
119667
|
},
|
|
119530
119668
|
dependencies: {
|
|
119531
|
-
"@percher/client": "^0.2.
|
|
119532
|
-
"@percher/core": "^0.4.
|
|
119533
|
-
"@percher/toml": "^0.1.
|
|
119669
|
+
"@percher/client": "^0.2.18",
|
|
119670
|
+
"@percher/core": "^0.4.22",
|
|
119671
|
+
"@percher/toml": "^0.1.7",
|
|
119534
119672
|
cac: "^7.0.0",
|
|
119535
119673
|
picocolors: "^1.1.1"
|
|
119536
119674
|
},
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "percher",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
4
4
|
"description": "CLI for the Percher hosting platform — publish apps with one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"typecheck": "tsc --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@percher/client": "^0.2.
|
|
28
|
-
"@percher/core": "^0.4.
|
|
29
|
-
"@percher/toml": "^0.1.
|
|
27
|
+
"@percher/client": "^0.2.18",
|
|
28
|
+
"@percher/core": "^0.4.22",
|
|
29
|
+
"@percher/toml": "^0.1.7",
|
|
30
30
|
"cac": "^7.0.0",
|
|
31
31
|
"picocolors": "^1.1.1"
|
|
32
32
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "percher",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.19",
|
|
4
4
|
"description": "CLI for the Percher hosting platform — publish apps with one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"typecheck": "tsc --noEmit"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@percher/client": "^0.2.
|
|
28
|
-
"@percher/core": "^0.4.
|
|
29
|
-
"@percher/toml": "^0.1.
|
|
27
|
+
"@percher/client": "^0.2.18",
|
|
28
|
+
"@percher/core": "^0.4.22",
|
|
29
|
+
"@percher/toml": "^0.1.7",
|
|
30
30
|
"cac": "^7.0.0",
|
|
31
31
|
"picocolors": "^1.1.1"
|
|
32
32
|
},
|