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.
@@ -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
- const suggestion = generateName(basename3(ctx.cwd));
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
- if (isSuspiciousAutoName(suggestion) && interactive) {
110279
- const answer = (await ctx.prompt(`Suggested app name: '${suggestion}'. Press Enter to accept, or type a different name: `, { default: suggestion })).trim();
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 (isSuspiciousAutoName(suggestion)) {
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: auto-generated app name '${suggestion}' looks like a temp-dir slug — set [app].name in percher.toml or pass --name to override.
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 import_cross_spawn2 = __toESM(require_cross_spawn(), 1);
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 = import_cross_spawn2.default(cmd, args, {
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.17",
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.16",
119532
- "@percher/core": "^0.4.18",
119533
- "@percher/toml": "^0.1.5",
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.17",
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.16",
28
- "@percher/core": "^0.4.18",
29
- "@percher/toml": "^0.1.5",
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.17",
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.16",
28
- "@percher/core": "^0.4.18",
29
- "@percher/toml": "^0.1.5",
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
  },