percher 0.5.12 → 0.5.15

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.
@@ -104733,7 +104733,15 @@ var percherConfigSchema = exports_external.object({
104733
104733
  crons: cronsSchema.optional(),
104734
104734
  addons: addonsSchema.optional(),
104735
104735
  checks: exports_external.record(exports_external.string(), checkSchema).optional()
104736
- }).strict();
104736
+ }).strict().superRefine((cfg, ctx) => {
104737
+ if (cfg.app?.runtime === "static" && cfg.build?.command) {
104738
+ ctx.addIssue({
104739
+ code: exports_external.ZodIssueCode.custom,
104740
+ path: ["build", "command"],
104741
+ message: 'runtime = "static" serves pre-built files and does not run a build command. Remove [build].command (commit the built output), or switch to runtime = "docker" for a build step.'
104742
+ });
104743
+ }
104744
+ });
104737
104745
 
104738
104746
  // ../toml/dist/parse.js
104739
104747
  function parse5(source) {
@@ -106572,10 +106580,10 @@ class LogsResource {
106572
106580
  const query = buildLogFilterQuery(options ?? {}, { lines: String(lines) });
106573
106581
  return this.http.get(`/apps/${encodeURIComponent(appId)}/logs?${query}`);
106574
106582
  }
106575
- streamRaw(appRef, options) {
106583
+ streamRaw(appRef, options, signal) {
106576
106584
  const query = buildLogFilterQuery(options ?? {});
106577
106585
  const suffix = query ? `?${query}` : "";
106578
- return this.http.stream(`/apps/${encodeURIComponent(appRef)}/logs/stream${suffix}`);
106586
+ return this.http.stream(`/apps/${encodeURIComponent(appRef)}/logs/stream${suffix}`, signal);
106579
106587
  }
106580
106588
  async* stream(appId, options) {
106581
106589
  const query = buildLogFilterQuery(options ?? {});
@@ -107267,6 +107275,7 @@ function recoveryFromErrorClass(errorClass, failure = {}) {
107267
107275
  switch (errorClass) {
107268
107276
  case "missing_env":
107269
107277
  return recoveryEnv({
107278
+ app: failure.appName,
107270
107279
  keys: failure.missingEnvVars ?? [],
107271
107280
  reasonCode: "missing_env"
107272
107281
  });
@@ -107647,7 +107656,7 @@ var patterns = [
107647
107656
  result: {
107648
107657
  title: "Health check failed",
107649
107658
  explanation: "Your app started but did not respond to the health check endpoint in time.",
107650
- suggestion: "Make sure your app listens on process.env.PORT and returns HTTP 200 on the health path. Then publish again.",
107659
+ suggestion: "Make sure your app listens on the injected port (process.env.PORT) and that your configured health path ([web].health in percher.toml, default '/') returns HTTP 200. Run `percher doctor --app <name>` for deeper analysis, then publish again.",
107651
107660
  errorClass: "health_check_timeout",
107652
107661
  phase: "health_check",
107653
107662
  cause: "timeout",
@@ -107961,6 +107970,7 @@ var DEFAULT_IGNORE = [
107961
107970
  "*.log",
107962
107971
  ".DS_Store"
107963
107972
  ];
107973
+ var ALWAYS_IGNORE_SECRETS = [".env", ".env.*"];
107964
107974
  function* walk(dir, baseDir, ig) {
107965
107975
  const entries = readdirSync2(dir);
107966
107976
  for (const name of entries) {
@@ -108026,14 +108036,25 @@ function buildTarball(fileBuffers) {
108026
108036
  const nodeStream = pack.pipe(gzip);
108027
108037
  const webStream = Readable.toWeb(nodeStream);
108028
108038
  const topFiles = [...fileBuffers].sort((a, b) => b.size - a.size).slice(0, 5).map((f) => ({ path: f.path, size: f.size }));
108039
+ const entrySizes = new Map;
108040
+ for (const f of fileBuffers) {
108041
+ const slash = f.path.indexOf("/");
108042
+ const key = slash === -1 ? f.path : `${f.path.slice(0, slash)}/`;
108043
+ entrySizes.set(key, (entrySizes.get(key) ?? 0) + f.size);
108044
+ }
108045
+ const topEntries = [...entrySizes.entries()].map(([path, size]) => ({ path, size, isDir: path.endsWith("/") })).sort((a, b) => b.size - a.size).slice(0, 5);
108029
108046
  return {
108030
108047
  stream: webStream,
108031
108048
  bytes: totalBytes,
108032
108049
  fileCount: fileBuffers.length,
108033
108050
  topFiles,
108051
+ topEntries,
108034
108052
  contentHash
108035
108053
  };
108036
108054
  }
108055
+ function formatBiggestEntries(entries) {
108056
+ return entries.map((e) => `${e.path} ${(e.size / 1024 / 1024).toFixed(1)} MB`).join(", ");
108057
+ }
108037
108058
  async function createTarball(options) {
108038
108059
  if (isFilesOptions(options)) {
108039
108060
  return createTarballFromFiles(options.files, options.config);
@@ -108044,8 +108065,13 @@ async function createTarball(options) {
108044
108065
  if (existsSync6(gitignorePath)) {
108045
108066
  ig.add(readFileSync6(gitignorePath, "utf8"));
108046
108067
  }
108068
+ const percherignorePath = join10(options.cwd, ".percherignore");
108069
+ if (existsSync6(percherignorePath)) {
108070
+ ig.add(readFileSync6(percherignorePath, "utf8"));
108071
+ }
108047
108072
  if (options.extraIgnore)
108048
108073
  ig.add(options.extraIgnore);
108074
+ ig.add(ALWAYS_IGNORE_SECRETS);
108049
108075
  const fileBuffers = [];
108050
108076
  for (const rel of walk(options.cwd, options.cwd, ig)) {
108051
108077
  const data2 = readFileSync6(join10(options.cwd, rel));
@@ -114641,6 +114667,27 @@ function tomlErrorToRecoveryProblems(err) {
114641
114667
  // ../core/dist/commands/env-scan.js
114642
114668
  import { readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync3 } from "node:fs";
114643
114669
  import { join as join22 } from "node:path";
114670
+ function platformInjectedClientEnvKeys(config2) {
114671
+ const data2 = config2.data;
114672
+ if (!data2)
114673
+ return [];
114674
+ switch (data2.mode) {
114675
+ case "pocketbase":
114676
+ return ["VITE_POCKETBASE_URL", "VITE_PERCHER_AI_URL"];
114677
+ case "convex":
114678
+ return data2.convex?.deployment_url ? ["VITE_CONVEX_URL"] : [];
114679
+ case "supabase": {
114680
+ const keys = [];
114681
+ if (data2.supabase?.url)
114682
+ keys.push("VITE_SUPABASE_URL");
114683
+ if (data2.supabase?.anon_key)
114684
+ keys.push("VITE_SUPABASE_ANON_KEY");
114685
+ return keys;
114686
+ }
114687
+ default:
114688
+ return [];
114689
+ }
114690
+ }
114644
114691
  var SOURCE_EXTS = new Set([
114645
114692
  ".ts",
114646
114693
  ".tsx",
@@ -115297,10 +115344,10 @@ ${bullets}`,
115297
115344
  error: {
115298
115345
  title: "Repository too large",
115299
115346
  explanation: `The project is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, which exceeds the 500 MB limit.`,
115300
- suggestion: `Add large files/folders to .gitignore. Biggest: ${tarball.topFiles.map((f) => f.path).join(", ")}`
115347
+ suggestion: `Add large files/folders to .gitignore or .percherignore. Biggest: ${formatBiggestEntries(tarball.topEntries)}`
115301
115348
  },
115302
115349
  recovery: recoveryAsk({
115303
- prompt: `Repository is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, which exceeds the 500 MB upload limit. Add large files/folders to .gitignore (biggest: ${tarball.topFiles.map((f) => f.path).join(", ")}) and try again.`,
115350
+ 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.`,
115304
115351
  reasonCode: "unknown"
115305
115352
  }),
115306
115353
  summary: `Repository too large (${(tarball.bytes / 1024 / 1024).toFixed(1)} MB exceeds 500 MB limit).`,
@@ -115309,7 +115356,7 @@ ${bullets}`,
115309
115356
  };
115310
115357
  }
115311
115358
  if (!input.force && (tarball.fileCount > SUSPICIOUS_FILES || tarball.bytes > SUSPICIOUS_BYTES)) {
115312
- ctx.status(`Warning: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB — auto-continuing (MCP mode).`);
115359
+ 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.`);
115313
115360
  }
115314
115361
  emitPreflight(ctx, config2, {
115315
115362
  fileCount: tarball.fileCount,
@@ -115340,6 +115387,8 @@ ${bullets}`,
115340
115387
  let missingBuildEnvKeys = [];
115341
115388
  try {
115342
115389
  const existingEnvKeys = new Set(Object.keys(await ctx.client.env.list(app.id)));
115390
+ for (const k of platformInjectedClientEnvKeys(config2))
115391
+ existingEnvKeys.add(k);
115343
115392
  missingBuildEnvKeys = scanForMissingBuildEnvRefs(ctx.cwd, existingEnvKeys);
115344
115393
  } catch {}
115345
115394
  if (missingBuildEnvKeys.length > 0 && !input.force) {
@@ -115968,17 +116017,17 @@ async function push(ctx, input = {}, internals = {}) {
115968
116017
  if (tarball.bytes > MAX_TARBALL_BYTES) {
115969
116018
  throw new PercherCoreError(`Repository is larger than 500 MB (current: ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB)`, {
115970
116019
  code: "push.too-large",
115971
- hint: `Biggest files: ${tarball.topFiles.map((f) => f.path).join(", ")}`,
116020
+ hint: `Biggest: ${formatBiggestEntries(tarball.topEntries)}`,
115972
116021
  recovery: {
115973
116022
  ...recoveryAsk({
115974
- prompt: `Repository is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, exceeding the 500 MB limit. Add large files/folders to .gitignore (biggest: ${tarball.topFiles.map((f) => f.path).join(", ")}) and re-run.`,
116023
+ prompt: `Repository is ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB, exceeding the 500 MB limit. Add large files/folders to .gitignore or .percherignore (biggest: ${formatBiggestEntries(tarball.topEntries)}) and re-run.`,
115975
116024
  reasonCode: "unknown"
115976
116025
  })
115977
116026
  }
115978
116027
  });
115979
116028
  }
115980
116029
  if (!input.force && (tarball.fileCount > SUSPICIOUS_FILES2 || tarball.bytes > SUSPICIOUS_BYTES2)) {
115981
- ctx.status(`This looks suspicious: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB. Are node_modules / dist excluded?`);
116030
+ ctx.status(`This looks suspicious: ${tarball.fileCount} files, ${(tarball.bytes / 1024 / 1024).toFixed(1)} MB. Biggest: ${formatBiggestEntries(tarball.topEntries)}. Are node_modules / dist excluded?`);
115982
116031
  const answer = await ctx.prompt("Continue anyway? [y/N]", { default: "n" });
115983
116032
  if (!/^y(es)?$/i.test(answer.trim())) {
115984
116033
  throw new PercherCoreError("Push aborted — looked suspicious", {
@@ -117280,6 +117329,9 @@ var BLOCKED_APP_NAMES = new Set([
117280
117329
  "caddy",
117281
117330
  "git",
117282
117331
  "percher",
117332
+ "mcp",
117333
+ "preview",
117334
+ "metrics",
117283
117335
  "login",
117284
117336
  "signin",
117285
117337
  "signup",
@@ -119308,7 +119360,7 @@ async function renderError(stderr, error48) {
119308
119360
  // package.json
119309
119361
  var package_default = {
119310
119362
  name: "percher",
119311
- version: "0.5.12",
119363
+ version: "0.5.15",
119312
119364
  description: "CLI for the Percher hosting platform — publish apps with one command",
119313
119365
  type: "module",
119314
119366
  bin: {
@@ -119333,7 +119385,7 @@ var package_default = {
119333
119385
  },
119334
119386
  dependencies: {
119335
119387
  "@percher/client": "^0.2.16",
119336
- "@percher/core": "^0.4.16",
119388
+ "@percher/core": "^0.4.18",
119337
119389
  "@percher/toml": "^0.1.5",
119338
119390
  cac: "^7.0.0",
119339
119391
  picocolors: "^1.1.1"
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "percher",
3
- "version": "0.5.12",
3
+ "version": "0.5.15",
4
4
  "description": "CLI for the Percher hosting platform \u2014 publish apps with one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@percher/client": "^0.2.16",
28
- "@percher/core": "^0.4.16",
28
+ "@percher/core": "^0.4.18",
29
29
  "@percher/toml": "^0.1.5",
30
30
  "cac": "^7.0.0",
31
31
  "picocolors": "^1.1.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "percher",
3
- "version": "0.5.12",
3
+ "version": "0.5.15",
4
4
  "description": "CLI for the Percher hosting platform \u2014 publish apps with one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@percher/client": "^0.2.16",
28
- "@percher/core": "^0.4.16",
28
+ "@percher/core": "^0.4.18",
29
29
  "@percher/toml": "^0.1.5",
30
30
  "cac": "^7.0.0",
31
31
  "picocolors": "^1.1.1"