@pushto/cli 0.2.0 → 0.4.6

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.
Files changed (188) hide show
  1. package/dist/commands/__tests__/deploy-domain.test.d.ts +2 -0
  2. package/dist/commands/__tests__/deploy-domain.test.d.ts.map +1 -0
  3. package/dist/commands/__tests__/deploy-domain.test.js +41 -0
  4. package/dist/commands/__tests__/deploy-domain.test.js.map +1 -0
  5. package/dist/commands/__tests__/headless-smoke.test.d.ts +2 -0
  6. package/dist/commands/__tests__/headless-smoke.test.d.ts.map +1 -0
  7. package/dist/commands/__tests__/headless-smoke.test.js +110 -0
  8. package/dist/commands/__tests__/headless-smoke.test.js.map +1 -0
  9. package/dist/commands/auth.d.ts +2 -0
  10. package/dist/commands/auth.d.ts.map +1 -0
  11. package/dist/commands/auth.js +77 -0
  12. package/dist/commands/auth.js.map +1 -0
  13. package/dist/commands/cron.d.ts +2 -0
  14. package/dist/commands/cron.d.ts.map +1 -0
  15. package/dist/commands/cron.js +157 -0
  16. package/dist/commands/cron.js.map +1 -0
  17. package/dist/commands/db.d.ts +4 -0
  18. package/dist/commands/db.d.ts.map +1 -0
  19. package/dist/commands/db.js +63 -0
  20. package/dist/commands/db.js.map +1 -0
  21. package/dist/commands/deploy.d.ts +16 -1
  22. package/dist/commands/deploy.d.ts.map +1 -1
  23. package/dist/commands/deploy.js +344 -68
  24. package/dist/commands/deploy.js.map +1 -1
  25. package/dist/commands/doctor.d.ts.map +1 -1
  26. package/dist/commands/doctor.js +401 -69
  27. package/dist/commands/doctor.js.map +1 -1
  28. package/dist/commands/domain.d.ts.map +1 -1
  29. package/dist/commands/domain.js +70 -18
  30. package/dist/commands/domain.js.map +1 -1
  31. package/dist/commands/echo.d.ts +2 -0
  32. package/dist/commands/echo.d.ts.map +1 -0
  33. package/dist/commands/echo.js +227 -0
  34. package/dist/commands/echo.js.map +1 -0
  35. package/dist/commands/env.d.ts +3 -1
  36. package/dist/commands/env.d.ts.map +1 -1
  37. package/dist/commands/env.js +76 -50
  38. package/dist/commands/env.js.map +1 -1
  39. package/dist/commands/init.d.ts +3 -1
  40. package/dist/commands/init.d.ts.map +1 -1
  41. package/dist/commands/init.js +58 -11
  42. package/dist/commands/init.js.map +1 -1
  43. package/dist/commands/login.d.ts.map +1 -1
  44. package/dist/commands/login.js +80 -39
  45. package/dist/commands/login.js.map +1 -1
  46. package/dist/commands/logs.d.ts +3 -1
  47. package/dist/commands/logs.d.ts.map +1 -1
  48. package/dist/commands/logs.js +77 -21
  49. package/dist/commands/logs.js.map +1 -1
  50. package/dist/commands/mail.d.ts +2 -0
  51. package/dist/commands/mail.d.ts.map +1 -0
  52. package/dist/commands/mail.js +105 -0
  53. package/dist/commands/mail.js.map +1 -0
  54. package/dist/commands/open.d.ts.map +1 -1
  55. package/dist/commands/open.js +32 -8
  56. package/dist/commands/open.js.map +1 -1
  57. package/dist/commands/preview.d.ts +22 -0
  58. package/dist/commands/preview.d.ts.map +1 -0
  59. package/dist/commands/preview.js +223 -0
  60. package/dist/commands/preview.js.map +1 -0
  61. package/dist/commands/status.d.ts +3 -1
  62. package/dist/commands/status.d.ts.map +1 -1
  63. package/dist/commands/status.js +62 -12
  64. package/dist/commands/status.js.map +1 -1
  65. package/dist/commands/upgrade.d.ts.map +1 -1
  66. package/dist/commands/upgrade.js +73 -10
  67. package/dist/commands/upgrade.js.map +1 -1
  68. package/dist/commands/use.d.ts +2 -0
  69. package/dist/commands/use.d.ts.map +1 -0
  70. package/dist/commands/use.js +108 -0
  71. package/dist/commands/use.js.map +1 -0
  72. package/dist/commands/vault.d.ts +2 -0
  73. package/dist/commands/vault.d.ts.map +1 -0
  74. package/dist/commands/vault.js +119 -0
  75. package/dist/commands/vault.js.map +1 -0
  76. package/dist/commands/whoami.d.ts.map +1 -1
  77. package/dist/commands/whoami.js +12 -1
  78. package/dist/commands/whoami.js.map +1 -1
  79. package/dist/index.js +123 -13
  80. package/dist/index.js.map +1 -1
  81. package/dist/lib/__tests__/build-runner.test.d.ts +2 -0
  82. package/dist/lib/__tests__/build-runner.test.d.ts.map +1 -0
  83. package/dist/lib/__tests__/build-runner.test.js +119 -0
  84. package/dist/lib/__tests__/build-runner.test.js.map +1 -0
  85. package/dist/lib/__tests__/cron-tail.test.d.ts +2 -0
  86. package/dist/lib/__tests__/cron-tail.test.d.ts.map +1 -0
  87. package/dist/lib/__tests__/cron-tail.test.js +27 -0
  88. package/dist/lib/__tests__/cron-tail.test.js.map +1 -0
  89. package/dist/lib/__tests__/detect-static-framework.test.d.ts +2 -0
  90. package/dist/lib/__tests__/detect-static-framework.test.d.ts.map +1 -0
  91. package/dist/lib/__tests__/detect-static-framework.test.js +146 -0
  92. package/dist/lib/__tests__/detect-static-framework.test.js.map +1 -0
  93. package/dist/lib/__tests__/errors.test.d.ts +2 -0
  94. package/dist/lib/__tests__/errors.test.d.ts.map +1 -0
  95. package/dist/lib/__tests__/errors.test.js +56 -0
  96. package/dist/lib/__tests__/errors.test.js.map +1 -0
  97. package/dist/lib/__tests__/interactive.test.d.ts +2 -0
  98. package/dist/lib/__tests__/interactive.test.d.ts.map +1 -0
  99. package/dist/lib/__tests__/interactive.test.js +79 -0
  100. package/dist/lib/__tests__/interactive.test.js.map +1 -0
  101. package/dist/lib/__tests__/output.test.d.ts +2 -0
  102. package/dist/lib/__tests__/output.test.d.ts.map +1 -0
  103. package/dist/lib/__tests__/output.test.js +144 -0
  104. package/dist/lib/__tests__/output.test.js.map +1 -0
  105. package/dist/lib/__tests__/prepare-artifact.test.d.ts +2 -0
  106. package/dist/lib/__tests__/prepare-artifact.test.d.ts.map +1 -0
  107. package/dist/lib/__tests__/prepare-artifact.test.js +55 -0
  108. package/dist/lib/__tests__/prepare-artifact.test.js.map +1 -0
  109. package/dist/lib/__tests__/preview-args.test.d.ts +2 -0
  110. package/dist/lib/__tests__/preview-args.test.d.ts.map +1 -0
  111. package/dist/lib/__tests__/preview-args.test.js +37 -0
  112. package/dist/lib/__tests__/preview-args.test.js.map +1 -0
  113. package/dist/lib/api.d.ts +2 -0
  114. package/dist/lib/api.d.ts.map +1 -1
  115. package/dist/lib/api.js +38 -5
  116. package/dist/lib/api.js.map +1 -1
  117. package/dist/lib/ask.d.ts +15 -0
  118. package/dist/lib/ask.d.ts.map +1 -0
  119. package/dist/lib/ask.js +24 -0
  120. package/dist/lib/ask.js.map +1 -0
  121. package/dist/lib/build-runner.d.ts +25 -0
  122. package/dist/lib/build-runner.d.ts.map +1 -0
  123. package/dist/lib/build-runner.js +141 -0
  124. package/dist/lib/build-runner.js.map +1 -0
  125. package/dist/lib/config.d.ts +6 -0
  126. package/dist/lib/config.d.ts.map +1 -1
  127. package/dist/lib/config.js +13 -2
  128. package/dist/lib/config.js.map +1 -1
  129. package/dist/lib/cron-tail.d.ts +10 -0
  130. package/dist/lib/cron-tail.d.ts.map +1 -0
  131. package/dist/lib/cron-tail.js +5 -0
  132. package/dist/lib/cron-tail.js.map +1 -0
  133. package/dist/lib/detect-static-framework.d.ts +31 -0
  134. package/dist/lib/detect-static-framework.d.ts.map +1 -0
  135. package/dist/lib/detect-static-framework.js +96 -0
  136. package/dist/lib/detect-static-framework.js.map +1 -0
  137. package/dist/lib/env-parse.d.ts +48 -0
  138. package/dist/lib/env-parse.d.ts.map +1 -0
  139. package/dist/lib/env-parse.js +91 -0
  140. package/dist/lib/env-parse.js.map +1 -0
  141. package/dist/lib/errors.d.ts +111 -0
  142. package/dist/lib/errors.d.ts.map +1 -0
  143. package/dist/lib/errors.js +64 -0
  144. package/dist/lib/errors.js.map +1 -0
  145. package/dist/lib/file-walker.d.ts +23 -0
  146. package/dist/lib/file-walker.d.ts.map +1 -0
  147. package/dist/lib/file-walker.js +114 -0
  148. package/dist/lib/file-walker.js.map +1 -0
  149. package/dist/lib/interactive.d.ts +13 -0
  150. package/dist/lib/interactive.d.ts.map +1 -0
  151. package/dist/lib/interactive.js +24 -0
  152. package/dist/lib/interactive.js.map +1 -0
  153. package/dist/lib/output.d.ts +24 -0
  154. package/dist/lib/output.d.ts.map +1 -0
  155. package/dist/lib/output.js +71 -0
  156. package/dist/lib/output.js.map +1 -0
  157. package/dist/lib/prepare-artifact.d.ts +22 -0
  158. package/dist/lib/prepare-artifact.d.ts.map +1 -0
  159. package/dist/lib/prepare-artifact.js +26 -0
  160. package/dist/lib/prepare-artifact.js.map +1 -0
  161. package/dist/lib/preview-args.d.ts +20 -0
  162. package/dist/lib/preview-args.d.ts.map +1 -0
  163. package/dist/lib/preview-args.js +19 -0
  164. package/dist/lib/preview-args.js.map +1 -0
  165. package/dist/lib/resolve-slug.d.ts.map +1 -1
  166. package/dist/lib/resolve-slug.js +9 -2
  167. package/dist/lib/resolve-slug.js.map +1 -1
  168. package/dist/lib/safe-json.d.ts +7 -2
  169. package/dist/lib/safe-json.d.ts.map +1 -1
  170. package/dist/lib/safe-json.js +23 -4
  171. package/dist/lib/safe-json.js.map +1 -1
  172. package/dist/lib/update-check.d.ts +17 -0
  173. package/dist/lib/update-check.d.ts.map +1 -0
  174. package/dist/lib/update-check.js +81 -0
  175. package/dist/lib/update-check.js.map +1 -0
  176. package/dist/lib/upload-limits.d.ts +17 -0
  177. package/dist/lib/upload-limits.d.ts.map +1 -0
  178. package/dist/lib/upload-limits.js +17 -0
  179. package/dist/lib/upload-limits.js.map +1 -0
  180. package/dist/lib/zip-project.d.ts +19 -0
  181. package/dist/lib/zip-project.d.ts.map +1 -0
  182. package/dist/lib/zip-project.js +39 -0
  183. package/dist/lib/zip-project.js.map +1 -0
  184. package/dist/version.d.ts +2 -0
  185. package/dist/version.d.ts.map +1 -0
  186. package/dist/version.js +16 -0
  187. package/dist/version.js.map +1 -0
  188. package/package.json +5 -8
@@ -0,0 +1,114 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import ignore from 'ignore';
4
+ // Always-exclude footguns: things that should never be deployed regardless of
5
+ // what the user's gitignore says. Catches secrets, pushto-internal files, and
6
+ // universally non-deployable build/cache artifacts even if the user forgot
7
+ // to gitignore them. Patterns without a slash match at any directory level
8
+ // per gitignore semantics — so `.venv` here also catches `sdks/python/.venv`
9
+ // (the chartmuse-engine case that had us shipping a 76MB zip).
10
+ //
11
+ // Conservative: only includes things that are NEVER the deployable artifact.
12
+ // `dist`, `build`, `out` are intentionally NOT here — for static sites those
13
+ // ARE what gets deployed.
14
+ export const ALWAYS_IGNORE = [
15
+ // pushto-internal + secrets
16
+ '.git',
17
+ '.pushto',
18
+ '.env',
19
+ '.env.local',
20
+ '.env.*.local',
21
+ '.DS_Store',
22
+ // Node
23
+ 'node_modules',
24
+ '.next',
25
+ '.vercel',
26
+ '.turbo',
27
+ // Python — venvs (~hundreds of MB), bytecode (regenerated on import),
28
+ // and test/type-check caches. None of these are ever deployed.
29
+ '.venv',
30
+ 'venv',
31
+ '__pycache__',
32
+ '*.pyc',
33
+ '.pytest_cache',
34
+ '.mypy_cache',
35
+ '.ruff_cache',
36
+ // Rust / Java / generic build dirs — multi-GB build output. Source-only
37
+ // deploys; if the user wants to ship a prebuilt binary, they put it
38
+ // somewhere other than `target/`.
39
+ 'target',
40
+ ];
41
+ // Build an ignore filter that combines ALWAYS_IGNORE with the project's own
42
+ // .gitignore and an optional .pushtoignore. Both files use gitignore syntax
43
+ // (negations, glob patterns, dir-only `foo/` markers).
44
+ //
45
+ // This is what unblocks non-Node projects: every Rust project has `target/`
46
+ // in .gitignore, every Python project has `__pycache__/` and `.venv/`, every
47
+ // Go project has `bin/`. Without reading gitignore, the zipper walked into
48
+ // those and either hit the 500MB cap or ground to a halt on tens of
49
+ // thousands of intermediate files.
50
+ export const loadIgnoreFilter = (rootDir) => {
51
+ const ig = ignore().add(ALWAYS_IGNORE);
52
+ const gitignorePath = path.join(rootDir, '.gitignore');
53
+ if (fs.existsSync(gitignorePath)) {
54
+ ig.add(fs.readFileSync(gitignorePath, 'utf-8'));
55
+ }
56
+ const pushtoignorePath = path.join(rootDir, '.pushtoignore');
57
+ if (fs.existsSync(pushtoignorePath)) {
58
+ ig.add(fs.readFileSync(pushtoignorePath, 'utf-8'));
59
+ }
60
+ return ig;
61
+ };
62
+ /**
63
+ * Walk a project directory using the same ignore semantics deploy.ts uses
64
+ * to build the deploy zip. Skips symlinks (traversal protection) and
65
+ * caps depth at 20.
66
+ *
67
+ * Both deploy.ts (zip the matched files) and doctor.ts (preview the
68
+ * matched files: count, total size, biggest) call this. If the two ever
69
+ * disagreed, doctor's "looks fine" would mismatch deploy's "exceeds limit"
70
+ * — frustrating to debug. One source = one truth.
71
+ */
72
+ export const walkProject = (rootDir) => {
73
+ const ig = loadIgnoreFilter(rootDir);
74
+ const files = [];
75
+ const MAX_DEPTH = 20;
76
+ const recurse = (dirPath, prefix, depth) => {
77
+ if (depth > MAX_DEPTH)
78
+ return;
79
+ let entries;
80
+ try {
81
+ entries = fs.readdirSync(dirPath, { withFileTypes: true });
82
+ }
83
+ catch {
84
+ return;
85
+ }
86
+ for (const entry of entries) {
87
+ if (entry.isSymbolicLink())
88
+ continue;
89
+ const archivePath = prefix ? `${prefix}/${entry.name}` : entry.name;
90
+ // Gitignore syntax: directory-only patterns (`target/`) match only when
91
+ // the test path ends in a slash. Always append `/` for directories so
92
+ // both file and dir patterns resolve correctly.
93
+ const testPath = entry.isDirectory() ? `${archivePath}/` : archivePath;
94
+ if (ig.ignores(testPath))
95
+ continue;
96
+ const fullPath = path.join(dirPath, entry.name);
97
+ if (entry.isFile()) {
98
+ try {
99
+ const stat = fs.statSync(fullPath);
100
+ files.push({ fullPath, archivePath, sizeBytes: stat.size });
101
+ }
102
+ catch {
103
+ // skip unreadable files
104
+ }
105
+ }
106
+ else if (entry.isDirectory()) {
107
+ recurse(fullPath, archivePath, depth + 1);
108
+ }
109
+ }
110
+ };
111
+ recurse(rootDir, '', 0);
112
+ return files;
113
+ };
114
+ //# sourceMappingURL=file-walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-walker.js","sourceRoot":"","sources":["../../src/lib/file-walker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The single source of truth for whether a command may block on a human.
3
+ *
4
+ * No command reads process.stdin.isTTY itself — a guard in
5
+ * apps/web/scripts/guard-cli-interactive.mjs fails the build if one does.
6
+ * That centralisation is the whole point: the deploy hang existed because
7
+ * one call site made this decision privately and got it wrong.
8
+ */
9
+ export declare const canPrompt: (flags?: {
10
+ json?: boolean;
11
+ yes?: boolean;
12
+ }) => boolean;
13
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/lib/interactive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,eAAO,MAAM,SAAS,GAAI,QAAQ;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,KAAG,OAIrE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The single source of truth for whether a command may block on a human.
3
+ *
4
+ * No command reads process.stdin.isTTY itself — a guard in
5
+ * apps/web/scripts/guard-cli-interactive.mjs fails the build if one does.
6
+ * That centralisation is the whole point: the deploy hang existed because
7
+ * one call site made this decision privately and got it wrong.
8
+ */
9
+ /** "", "0" and "false" all mean not-set, matching shell convention. */
10
+ const envFlagSet = (name) => {
11
+ const raw = process.env[name];
12
+ if (!raw)
13
+ return false;
14
+ const v = raw.toLowerCase();
15
+ return v !== '0' && v !== 'false';
16
+ };
17
+ export const canPrompt = (flags) => {
18
+ if (flags?.json || flags?.yes)
19
+ return false;
20
+ if (envFlagSet('CI') || envFlagSet('PUSHTO_NONINTERACTIVE'))
21
+ return false;
22
+ return Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY);
23
+ };
24
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/lib/interactive.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,uEAAuE;AACvE,MAAM,UAAU,GAAG,CAAC,IAAY,EAAW,EAAE;IAC3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,MAAM,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC5B,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAyC,EAAW,EAAE;IAC9E,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,GAAG;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,uBAAuB,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1E,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { PushtoError } from '@pushto/shared/errors';
2
+ import { buildError, type PushtoErrorCode } from './errors.js';
3
+ export interface OutputOpts {
4
+ json?: boolean;
5
+ }
6
+ /**
7
+ * Under --json, stdout carries exactly one JSON object and nothing else, so
8
+ * `pushto deploy --json | jq` works unfiltered. Everything a human would
9
+ * enjoy — spinners, colour, progress — goes to stderr instead.
10
+ *
11
+ * lib/api.ts already wrote its session-expired notice to stderr to keep user
12
+ * pipes clean; this module finishes that discipline for the whole spine.
13
+ */
14
+ /** Human-only progress. Never stdout; in json mode it still goes to stderr. */
15
+ export declare const progress: (line: string, opts: OutputOpts) => void;
16
+ /** ora writes to stdout by default. In json mode that would corrupt the payload. */
17
+ export declare const spinnerStream: (opts: OutputOpts) => NodeJS.WriteStream;
18
+ export declare const emitOk: (payload: Record<string, unknown> & {
19
+ human?: string;
20
+ }, opts: OutputOpts) => void;
21
+ export declare const emitErr: (err: PushtoError, opts: OutputOpts) => void;
22
+ /** Render the error and exit on the band its code derives. Never returns. */
23
+ export declare const fail: (code: PushtoErrorCode, human: string, opts: OutputOpts, extra?: Parameters<typeof buildError>[2]) => never;
24
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAe,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5E,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,EAAE,MAAM,UAAU,KAAG,IAEzD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,aAAa,GAAI,MAAM,UAAU,KAAG,MAAM,CAAC,WACX,CAAC;AAE9C,eAAO,MAAM,MAAM,GACjB,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACrD,MAAM,UAAU,KACf,IAOF,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,WAAW,EAAE,MAAM,UAAU,KAAG,IA4C5D,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,IAAI,GACf,MAAM,eAAe,EACrB,OAAO,MAAM,EACb,MAAM,UAAU,EAChB,QAAQ,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,KACvC,KAGF,CAAC"}
@@ -0,0 +1,71 @@
1
+ import chalk from 'chalk';
2
+ import { buildError, exitCodeFor } from './errors.js';
3
+ /**
4
+ * Under --json, stdout carries exactly one JSON object and nothing else, so
5
+ * `pushto deploy --json | jq` works unfiltered. Everything a human would
6
+ * enjoy — spinners, colour, progress — goes to stderr instead.
7
+ *
8
+ * lib/api.ts already wrote its session-expired notice to stderr to keep user
9
+ * pipes clean; this module finishes that discipline for the whole spine.
10
+ */
11
+ /** Human-only progress. Never stdout; in json mode it still goes to stderr. */
12
+ export const progress = (line, opts) => {
13
+ process.stderr.write(opts.json ? `${line}\n` : `${chalk.dim(line)}\n`);
14
+ };
15
+ /** ora writes to stdout by default. In json mode that would corrupt the payload. */
16
+ export const spinnerStream = (opts) => opts.json ? process.stderr : process.stdout;
17
+ export const emitOk = (payload, opts) => {
18
+ if (opts.json) {
19
+ const { human: _human, ...rest } = payload;
20
+ process.stdout.write(`${JSON.stringify({ ok: true, ...rest })}\n`);
21
+ return;
22
+ }
23
+ if (payload.human)
24
+ process.stdout.write(`${payload.human}\n`);
25
+ };
26
+ export const emitErr = (err, opts) => {
27
+ if (opts.json) {
28
+ // `prose` is a human-render hint carrying a {cmd} placeholder. Machines
29
+ // read label/cmd/href, so it is stripped here rather than shipped as a
30
+ // half-interpolated string a caller might print raw.
31
+ const machineFix = err.fix
32
+ ? {
33
+ label: err.fix.label,
34
+ ...(err.fix.cmd ? { cmd: err.fix.cmd } : {}),
35
+ ...(err.fix.href ? { href: err.fix.href } : {}),
36
+ }
37
+ : undefined;
38
+ // Keys are spread in a fixed order so the payload shape stays stable for
39
+ // consumers that diff or snapshot it. Optional keys are omitted, not set
40
+ // to undefined, because JSON.stringify would drop them inconsistently.
41
+ process.stdout.write(`${JSON.stringify({
42
+ ok: false,
43
+ ...(err.stage ? { stage: err.stage } : {}),
44
+ retryable: err.retryable,
45
+ ...(err.details ? { details: err.details } : {}),
46
+ error: { code: err.code, human: err.human, ...(machineFix ? { fix: machineFix } : {}) },
47
+ })}\n`);
48
+ return;
49
+ }
50
+ process.stderr.write(`${chalk.red(`> ${err.human}`)}\n`);
51
+ if (!err.fix)
52
+ return;
53
+ const target = err.fix.cmd ?? err.fix.href;
54
+ if (!target)
55
+ return;
56
+ // `prose` wins so hand-written copy survives the structured shape: the
57
+ // sentence is split on its single {cmd} placeholder and the command is
58
+ // highlighted in place, reproducing the original line exactly.
59
+ if (err.fix.prose) {
60
+ const [before = '', after = ''] = err.fix.prose.split('{cmd}');
61
+ process.stderr.write(`${chalk.dim(` ${before}`)}${chalk.cyan(target)}${chalk.dim(after)}\n`);
62
+ return;
63
+ }
64
+ process.stderr.write(`${chalk.dim(` ${err.fix.label}: `)}${chalk.cyan(target)}\n`);
65
+ };
66
+ /** Render the error and exit on the band its code derives. Never returns. */
67
+ export const fail = (code, human, opts, extra) => {
68
+ emitErr(buildError(code, human, extra), opts);
69
+ process.exit(exitCodeFor(code));
70
+ };
71
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The one entry point deploy + preview share: decide whether this
3
+ * directory deploys as-is (source) or gets built first (artifact).
4
+ * Keeping it here means `pushto` and `pushto preview` cannot drift —
5
+ * the exact failure the spec calls out (working deploys, blank previews).
6
+ */
7
+ export type ArtifactPrep = {
8
+ kind: 'source';
9
+ zipDir: string;
10
+ } | {
11
+ kind: 'artifact';
12
+ zipDir: string;
13
+ framework: string;
14
+ typeWarnings: string | null;
15
+ cleanup: () => void;
16
+ } | {
17
+ kind: 'failed';
18
+ message: string;
19
+ buildOutput: string;
20
+ };
21
+ export declare const prepareArtifact: (cwd: string, log: (line: string) => void) => Promise<ArtifactPrep>;
22
+ //# sourceMappingURL=prepare-artifact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-artifact.d.ts","sourceRoot":"","sources":["../../src/lib/prepare-artifact.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,GACzG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,eAAO,MAAM,eAAe,GAC1B,KAAK,MAAM,EACX,KAAK,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,KAC1B,OAAO,CAAC,YAAY,CAsBtB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { detectStaticFramework } from './detect-static-framework.js';
2
+ import { runStaticBuild, writeArtifactMeta } from './build-runner.js';
3
+ export const prepareArtifact = async (cwd, log) => {
4
+ const detection = detectStaticFramework(cwd);
5
+ if (!detection)
6
+ return { kind: 'source', zipDir: cwd };
7
+ const build = await runStaticBuild(cwd, detection, { log });
8
+ if (!build.ok)
9
+ return { kind: 'failed', message: build.message, buildOutput: build.buildOutput };
10
+ const cleanup = writeArtifactMeta(build.outputDir, {
11
+ framework: detection.framework,
12
+ spa: detection.spa,
13
+ });
14
+ // The marker must never outlive the command: registering cleanup on
15
+ // process exit covers every failure branch (process.exit calls
16
+ // included), so no call site can forget it. cleanup is idempotent.
17
+ process.once('exit', cleanup);
18
+ return {
19
+ kind: 'artifact',
20
+ zipDir: build.outputDir,
21
+ framework: detection.framework,
22
+ typeWarnings: build.typeWarnings,
23
+ cleanup,
24
+ };
25
+ };
26
+ //# sourceMappingURL=prepare-artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare-artifact.js","sourceRoot":"","sources":["../../src/lib/prepare-artifact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAatE,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,GAAW,EACX,GAA2B,EACJ,EAAE;IACzB,MAAM,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAEvD,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5D,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;IAEjG,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,EAAE;QACjD,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,GAAG,EAAE,SAAS,CAAC,GAAG;KACnB,CAAC,CAAC;IACH,oEAAoE;IACpE,+DAA+D;IAC/D,mEAAmE;IACnE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,KAAK,CAAC,SAAS;QACvB,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,OAAO;KACR,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The `pushto preview` action grammar, as one pure function.
3
+ *
4
+ * The command's help and docs/cli teach "(create, ls, rm)". Before this
5
+ * seam the dispatcher had no `create` verb — any unknown action word was
6
+ * treated as a directory, so the documented `pushto preview create` died
7
+ * with "not a directory: create". A bare positional directory
8
+ * (`pushto preview dist`) still works.
9
+ */
10
+ export type PreviewAction = {
11
+ kind: 'create';
12
+ dir: string;
13
+ } | {
14
+ kind: 'ls';
15
+ } | {
16
+ kind: 'rm';
17
+ ref: string | undefined;
18
+ };
19
+ export declare const resolvePreviewAction: (action: string, args: string[]) => PreviewAction;
20
+ //# sourceMappingURL=preview-args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-args.d.ts","sourceRoot":"","sources":["../../src/lib/preview-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAE5C,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,EAAE,KAAG,aAKrE,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The `pushto preview` action grammar, as one pure function.
3
+ *
4
+ * The command's help and docs/cli teach "(create, ls, rm)". Before this
5
+ * seam the dispatcher had no `create` verb — any unknown action word was
6
+ * treated as a directory, so the documented `pushto preview create` died
7
+ * with "not a directory: create". A bare positional directory
8
+ * (`pushto preview dist`) still works.
9
+ */
10
+ export const resolvePreviewAction = (action, args) => {
11
+ if (action === 'ls' || action === 'list')
12
+ return { kind: 'ls' };
13
+ if (action === 'rm' || action === 'delete')
14
+ return { kind: 'rm', ref: args[0] };
15
+ if (action === 'create')
16
+ return { kind: 'create', dir: args[0] ?? '.' };
17
+ return { kind: 'create', dir: action.length > 0 ? action : '.' };
18
+ };
19
+ //# sourceMappingURL=preview-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-args.js","sourceRoot":"","sources":["../../src/lib/preview-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,MAAc,EAAE,IAAc,EAAiB,EAAE;IACpF,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChE,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;IACxE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACnE,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-slug.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAO,MAAM,GAAG,SAavC,CAAC"}
1
+ {"version":3,"file":"resolve-slug.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AASA;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAO,MAAM,GAAG,SAiBvC,CAAC"}
@@ -1,6 +1,9 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { getProjectSlug } from './config.js';
4
+ /** Validate a slug is safe for use in URL paths (no traversal, no injection). */
5
+ const SAFE_SLUG_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
6
+ const isValidSlug = (slug) => slug.length >= 2 && slug.length <= 63 && SAFE_SLUG_RE.test(slug);
4
7
  /**
5
8
  * Resolve the project slug from:
6
9
  * 1. .pushto file in the current directory
@@ -12,13 +15,17 @@ export const resolveSlug = () => {
12
15
  try {
13
16
  const content = fs.readFileSync(pushtoFile, 'utf-8');
14
17
  const parsed = JSON.parse(content);
15
- if (parsed.slug)
18
+ if (typeof parsed.slug === 'string' && isValidSlug(parsed.slug)) {
16
19
  return parsed.slug;
20
+ }
17
21
  }
18
22
  catch {
19
23
  // No .pushto file or invalid JSON — fall through
20
24
  }
21
25
  // Fall back to global config
22
- return getProjectSlug();
26
+ const globalSlug = getProjectSlug();
27
+ if (globalSlug && isValidSlug(globalSlug))
28
+ return globalSlug;
29
+ return undefined;
23
30
  };
24
31
  //# sourceMappingURL=resolve-slug.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-slug.js","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAuB,EAAE;IAClD,gCAAgC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,6BAA6B;IAC7B,OAAO,cAAc,EAAE,CAAC;AAC1B,CAAC,CAAC"}
1
+ {"version":3,"file":"resolve-slug.js","sourceRoot":"","sources":["../../src/lib/resolve-slug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,iFAAiF;AACjF,MAAM,YAAY,GAAG,8BAA8B,CAAC;AACpD,MAAM,WAAW,GAAG,CAAC,IAAY,EAAW,EAAE,CAC5C,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEnE;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,GAAuB,EAAE;IAClD,gCAAgC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAChE,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,6BAA6B;IAC7B,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,IAAI,UAAU,IAAI,WAAW,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAC7D,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * Safely parse a Response as JSON.
3
- * Returns the parsed object, or a fallback error object if the response
4
- * isn't valid JSON (e.g., HTML error pages from the server).
3
+ * Returns the parsed object, or an `{ error }` envelope when the body
4
+ * isn't valid JSON. The error string includes the HTTP status, the
5
+ * request path, and a body preview so a downstream "> ${data.error}"
6
+ * print still tells the user (and us) what actually failed.
7
+ *
8
+ * Replaces the old "server returned non-JSON: " message that lost all
9
+ * context when the body was empty (e.g. an unhandled 500 from the API).
5
10
  */
6
11
  export declare const safeJson: <T = Record<string, unknown>>(res: Response) => Promise<T>;
7
12
  //# sourceMappingURL=safe-json.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-json.d.ts","sourceRoot":"","sources":["../../src/lib/safe-json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAU,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxD,KAAK,QAAQ,KACZ,OAAO,CAAC,CAAC,CAOX,CAAC"}
1
+ {"version":3,"file":"safe-json.d.ts","sourceRoot":"","sources":["../../src/lib/safe-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,GAAU,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxD,KAAK,QAAQ,KACZ,OAAO,CAAC,CAAC,CAuBX,CAAC"}
@@ -1,15 +1,34 @@
1
1
  /**
2
2
  * Safely parse a Response as JSON.
3
- * Returns the parsed object, or a fallback error object if the response
4
- * isn't valid JSON (e.g., HTML error pages from the server).
3
+ * Returns the parsed object, or an `{ error }` envelope when the body
4
+ * isn't valid JSON. The error string includes the HTTP status, the
5
+ * request path, and a body preview so a downstream "> ${data.error}"
6
+ * print still tells the user (and us) what actually failed.
7
+ *
8
+ * Replaces the old "server returned non-JSON: " message that lost all
9
+ * context when the body was empty (e.g. an unhandled 500 from the API).
5
10
  */
6
11
  export const safeJson = async (res) => {
7
12
  const text = await res.text();
13
+ if (text) {
14
+ try {
15
+ return JSON.parse(text);
16
+ }
17
+ catch {
18
+ // fall through
19
+ }
20
+ }
21
+ let path = '';
8
22
  try {
9
- return JSON.parse(text);
23
+ path = new URL(res.url).pathname;
10
24
  }
11
25
  catch {
12
- return { error: `server returned non-JSON: ${text.slice(0, 100)}` };
26
+ // res.url may be empty in some runtimes
13
27
  }
28
+ const where = path ? ` from ${path}` : '';
29
+ const error = text
30
+ ? `pushto.host returned ${res.status}${where}. body: ${text.slice(0, 200)}`
31
+ : `pushto.host returned ${res.status}${where} with an empty body — likely a server crash. try again, or email support@pushto.host if it sticks.`;
32
+ return { error };
14
33
  };
15
34
  //# sourceMappingURL=safe-json.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"safe-json.js","sourceRoot":"","sources":["../../src/lib/safe-json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAC3B,GAAa,EACD,EAAE;IACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,6BAA6B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAO,CAAC;IAC3E,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"safe-json.js","sourceRoot":"","sources":["../../src/lib/safe-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAC3B,GAAa,EACD,EAAE;IACd,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IAED,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,wCAAwC;IAC1C,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1C,MAAM,KAAK,GAAG,IAAI;QAChB,CAAC,CAAC,wBAAwB,GAAG,CAAC,MAAM,GAAG,KAAK,WAAW,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;QAC3E,CAAC,CAAC,wBAAwB,GAAG,CAAC,MAAM,GAAG,KAAK,oGAAoG,CAAC;IAEnJ,OAAO,EAAE,KAAK,EAAO,CAAC;AACxB,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ interface UpdateInfo {
2
+ current: string;
3
+ latest: string;
4
+ needsUpdate: boolean;
5
+ }
6
+ /**
7
+ * Check npm registry for a newer version of @pushto/cli.
8
+ * Caches the result for 24 hours to avoid slowing down every invocation.
9
+ * Returns null if the check was skipped (cached) or failed (network error).
10
+ */
11
+ export declare const checkForUpdate: (force?: boolean) => Promise<UpdateInfo | null>;
12
+ /** Read the version baked into this CLI build. The build script overwrites
13
+ * src/version.ts with the real value before each `bun build --compile`.
14
+ * Local dev (tsx src/index.ts) keeps the committed "0.0.0-dev". */
15
+ export declare const getCurrentVersion: () => string;
16
+ export {};
17
+ //# sourceMappingURL=update-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;CACtB;AAID;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,eAAa,KACZ,OAAO,CAAC,UAAU,GAAG,IAAI,CAiC3B,CAAC;AAoCF;;oEAEoE;AACpE,eAAO,MAAM,iBAAiB,QAAO,MAAiB,CAAC"}
@@ -0,0 +1,81 @@
1
+ import { config } from './config.js';
2
+ import { VERSION } from '../version.js';
3
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
4
+ /**
5
+ * Check npm registry for a newer version of @pushto/cli.
6
+ * Caches the result for 24 hours to avoid slowing down every invocation.
7
+ * Returns null if the check was skipped (cached) or failed (network error).
8
+ */
9
+ export const checkForUpdate = async (force = false) => {
10
+ const lastCheck = config.get('lastUpdateCheck');
11
+ if (!force && lastCheck && Date.now() - lastCheck < CHECK_INTERVAL_MS) {
12
+ // Return cached result if we checked recently
13
+ const cached = config.get('latestVersion');
14
+ if (cached) {
15
+ const current = getCurrentVersion();
16
+ return { current, latest: cached, needsUpdate: isNewer(cached, current) };
17
+ }
18
+ return null;
19
+ }
20
+ try {
21
+ const controller = new AbortController();
22
+ const timeout = setTimeout(() => controller.abort(), 3000);
23
+ const latest = await fetchLatestVersion(controller.signal);
24
+ clearTimeout(timeout);
25
+ if (!latest)
26
+ return null;
27
+ config.set('lastUpdateCheck', Date.now());
28
+ config.set('latestVersion', latest);
29
+ const current = getCurrentVersion();
30
+ return { current, latest, needsUpdate: isNewer(latest, current) };
31
+ }
32
+ catch {
33
+ // Network error, offline, timeout — don't bother the user
34
+ return null;
35
+ }
36
+ };
37
+ // Pick the right "latest version" source for how this CLI was installed.
38
+ // Homebrew binaries get versioned by GitHub releases on the homebrew-tap
39
+ // repo (the source repo is private). npm-installed CLIs check the npm
40
+ // registry. Mixing them caused the infinite "upgrade available → brew says
41
+ // already current → re-prompt" loop in <0.4.0.
42
+ const fetchLatestVersion = async (signal) => {
43
+ if (isBrewBinary()) {
44
+ const res = await fetch('https://api.github.com/repos/mydude-industries/homebrew-tap/releases/latest', { signal, headers: { Accept: 'application/vnd.github+json' } });
45
+ if (!res.ok)
46
+ return null;
47
+ const data = (await res.json());
48
+ return data.tag_name?.replace(/^v/, '') ?? null;
49
+ }
50
+ const res = await fetch('https://registry.npmjs.org/@pushto/cli/latest', { signal });
51
+ if (!res.ok)
52
+ return null;
53
+ const data = (await res.json());
54
+ return data.version ?? null;
55
+ };
56
+ const isBrewBinary = () => {
57
+ const exe = process.execPath;
58
+ return (exe.includes('/Cellar/') ||
59
+ exe.startsWith('/opt/homebrew/') ||
60
+ exe.includes('/linuxbrew/') ||
61
+ exe.includes('/home/linuxbrew/'));
62
+ };
63
+ /** Read the version baked into this CLI build. The build script overwrites
64
+ * src/version.ts with the real value before each `bun build --compile`.
65
+ * Local dev (tsx src/index.ts) keeps the committed "0.0.0-dev". */
66
+ export const getCurrentVersion = () => VERSION;
67
+ /** True if `a` is a newer semver than `b`. */
68
+ const isNewer = (a, b) => {
69
+ const pa = a.split('.').map(Number);
70
+ const pb = b.split('.').map(Number);
71
+ for (let i = 0; i < 3; i++) {
72
+ const av = pa[i] ?? 0;
73
+ const bv = pb[i] ?? 0;
74
+ if (av > bv)
75
+ return true;
76
+ if (av < bv)
77
+ return false;
78
+ }
79
+ return false;
80
+ };
81
+ //# sourceMappingURL=update-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/lib/update-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAQxC,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAE1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EACjC,KAAK,GAAG,KAAK,EACe,EAAE;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,iBAA0B,CAE1C,CAAC;IAEd,IAAI,CAAC,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,iBAAiB,EAAE,CAAC;QACtE,8CAA8C;QAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,eAAwB,CAAuB,CAAC;QAC1E,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;YACpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC3D,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,MAAM,CAAC,GAAG,CAAC,iBAA0B,EAAE,IAAI,CAAC,GAAG,EAAW,CAAC,CAAC;QAC5D,MAAM,CAAC,GAAG,CAAC,eAAwB,EAAE,MAAe,CAAC,CAAC;QAEtD,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;QACpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,yEAAyE;AACzE,yEAAyE;AACzE,sEAAsE;AACtE,2EAA2E;AAC3E,+CAA+C;AAC/C,MAAM,kBAAkB,GAAG,KAAK,EAAE,MAAmB,EAA0B,EAAE;IAC/E,IAAI,YAAY,EAAE,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,6EAA6E,EAC7E,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE,CAC/D,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0B,CAAC;QACzD,OAAO,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC;IAClD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,+CAA+C,EAC/C,EAAE,MAAM,EAAE,CACX,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAC;IACxD,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,GAAY,EAAE;IACjC,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC7B,OAAO,CACL,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;QACxB,GAAG,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAChC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CACjC,CAAC;AACJ,CAAC,CAAC;AAEF;;oEAEoE;AACpE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAW,EAAE,CAAC,OAAO,CAAC;AAEvD,8CAA8C;AAC9C,MAAM,OAAO,GAAG,CAAC,CAAS,EAAE,CAAS,EAAW,EAAE;IAChD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Upload-size cap that matches the server-side validation in
3
+ * apps/web/app/api/cli/projects/[slug]/upload/route.ts (line ~83).
4
+ *
5
+ * Single source of truth so doctor and deploy can't disagree:
6
+ * - doctor uses it to warn before the user even tries
7
+ * - deploy uses it to fail fast LOCALLY before wasting a ~30s upload
8
+ * that the server will 413 anyway
9
+ *
10
+ * If you bump this, bump the server check at the same time. Pre-fix,
11
+ * deploy.ts had its own MAX_ZIP_BYTES = 500MB constant — uploads
12
+ * between 50MB and 500MB went up the wire and got rejected after
13
+ * the long upload finished.
14
+ */
15
+ export declare const SERVER_UPLOAD_CAP_BYTES: number;
16
+ export declare const fmtMB: (bytes: number) => string;
17
+ //# sourceMappingURL=upload-limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-limits.d.ts","sourceRoot":"","sources":["../../src/lib/upload-limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,QAAmB,CAAC;AAExD,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MAAiD,CAAC"}