@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.
- package/dist/commands/__tests__/deploy-domain.test.d.ts +2 -0
- package/dist/commands/__tests__/deploy-domain.test.d.ts.map +1 -0
- package/dist/commands/__tests__/deploy-domain.test.js +41 -0
- package/dist/commands/__tests__/deploy-domain.test.js.map +1 -0
- package/dist/commands/__tests__/headless-smoke.test.d.ts +2 -0
- package/dist/commands/__tests__/headless-smoke.test.d.ts.map +1 -0
- package/dist/commands/__tests__/headless-smoke.test.js +110 -0
- package/dist/commands/__tests__/headless-smoke.test.js.map +1 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +77 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/cron.d.ts +2 -0
- package/dist/commands/cron.d.ts.map +1 -0
- package/dist/commands/cron.js +157 -0
- package/dist/commands/cron.js.map +1 -0
- package/dist/commands/db.d.ts +4 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +63 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/deploy.d.ts +16 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +344 -68
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +401 -69
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/domain.d.ts.map +1 -1
- package/dist/commands/domain.js +70 -18
- package/dist/commands/domain.js.map +1 -1
- package/dist/commands/echo.d.ts +2 -0
- package/dist/commands/echo.d.ts.map +1 -0
- package/dist/commands/echo.js +227 -0
- package/dist/commands/echo.js.map +1 -0
- package/dist/commands/env.d.ts +3 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +76 -50
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +58 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +80 -39
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logs.d.ts +3 -1
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +77 -21
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/mail.d.ts +2 -0
- package/dist/commands/mail.d.ts.map +1 -0
- package/dist/commands/mail.js +105 -0
- package/dist/commands/mail.js.map +1 -0
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +32 -8
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/preview.d.ts +22 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +223 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +62 -12
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +73 -10
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/commands/use.d.ts +2 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +108 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/commands/vault.d.ts +2 -0
- package/dist/commands/vault.d.ts.map +1 -0
- package/dist/commands/vault.js +119 -0
- package/dist/commands/vault.js.map +1 -0
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +12 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/index.js +123 -13
- package/dist/index.js.map +1 -1
- package/dist/lib/__tests__/build-runner.test.d.ts +2 -0
- package/dist/lib/__tests__/build-runner.test.d.ts.map +1 -0
- package/dist/lib/__tests__/build-runner.test.js +119 -0
- package/dist/lib/__tests__/build-runner.test.js.map +1 -0
- package/dist/lib/__tests__/cron-tail.test.d.ts +2 -0
- package/dist/lib/__tests__/cron-tail.test.d.ts.map +1 -0
- package/dist/lib/__tests__/cron-tail.test.js +27 -0
- package/dist/lib/__tests__/cron-tail.test.js.map +1 -0
- package/dist/lib/__tests__/detect-static-framework.test.d.ts +2 -0
- package/dist/lib/__tests__/detect-static-framework.test.d.ts.map +1 -0
- package/dist/lib/__tests__/detect-static-framework.test.js +146 -0
- package/dist/lib/__tests__/detect-static-framework.test.js.map +1 -0
- package/dist/lib/__tests__/errors.test.d.ts +2 -0
- package/dist/lib/__tests__/errors.test.d.ts.map +1 -0
- package/dist/lib/__tests__/errors.test.js +56 -0
- package/dist/lib/__tests__/errors.test.js.map +1 -0
- package/dist/lib/__tests__/interactive.test.d.ts +2 -0
- package/dist/lib/__tests__/interactive.test.d.ts.map +1 -0
- package/dist/lib/__tests__/interactive.test.js +79 -0
- package/dist/lib/__tests__/interactive.test.js.map +1 -0
- package/dist/lib/__tests__/output.test.d.ts +2 -0
- package/dist/lib/__tests__/output.test.d.ts.map +1 -0
- package/dist/lib/__tests__/output.test.js +144 -0
- package/dist/lib/__tests__/output.test.js.map +1 -0
- package/dist/lib/__tests__/prepare-artifact.test.d.ts +2 -0
- package/dist/lib/__tests__/prepare-artifact.test.d.ts.map +1 -0
- package/dist/lib/__tests__/prepare-artifact.test.js +55 -0
- package/dist/lib/__tests__/prepare-artifact.test.js.map +1 -0
- package/dist/lib/__tests__/preview-args.test.d.ts +2 -0
- package/dist/lib/__tests__/preview-args.test.d.ts.map +1 -0
- package/dist/lib/__tests__/preview-args.test.js +37 -0
- package/dist/lib/__tests__/preview-args.test.js.map +1 -0
- package/dist/lib/api.d.ts +2 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +38 -5
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/ask.d.ts +15 -0
- package/dist/lib/ask.d.ts.map +1 -0
- package/dist/lib/ask.js +24 -0
- package/dist/lib/ask.js.map +1 -0
- package/dist/lib/build-runner.d.ts +25 -0
- package/dist/lib/build-runner.d.ts.map +1 -0
- package/dist/lib/build-runner.js +141 -0
- package/dist/lib/build-runner.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +13 -2
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/cron-tail.d.ts +10 -0
- package/dist/lib/cron-tail.d.ts.map +1 -0
- package/dist/lib/cron-tail.js +5 -0
- package/dist/lib/cron-tail.js.map +1 -0
- package/dist/lib/detect-static-framework.d.ts +31 -0
- package/dist/lib/detect-static-framework.d.ts.map +1 -0
- package/dist/lib/detect-static-framework.js +96 -0
- package/dist/lib/detect-static-framework.js.map +1 -0
- package/dist/lib/env-parse.d.ts +48 -0
- package/dist/lib/env-parse.d.ts.map +1 -0
- package/dist/lib/env-parse.js +91 -0
- package/dist/lib/env-parse.js.map +1 -0
- package/dist/lib/errors.d.ts +111 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +64 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/file-walker.d.ts +23 -0
- package/dist/lib/file-walker.d.ts.map +1 -0
- package/dist/lib/file-walker.js +114 -0
- package/dist/lib/file-walker.js.map +1 -0
- package/dist/lib/interactive.d.ts +13 -0
- package/dist/lib/interactive.d.ts.map +1 -0
- package/dist/lib/interactive.js +24 -0
- package/dist/lib/interactive.js.map +1 -0
- package/dist/lib/output.d.ts +24 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +71 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/prepare-artifact.d.ts +22 -0
- package/dist/lib/prepare-artifact.d.ts.map +1 -0
- package/dist/lib/prepare-artifact.js +26 -0
- package/dist/lib/prepare-artifact.js.map +1 -0
- package/dist/lib/preview-args.d.ts +20 -0
- package/dist/lib/preview-args.d.ts.map +1 -0
- package/dist/lib/preview-args.js +19 -0
- package/dist/lib/preview-args.js.map +1 -0
- package/dist/lib/resolve-slug.d.ts.map +1 -1
- package/dist/lib/resolve-slug.js +9 -2
- package/dist/lib/resolve-slug.js.map +1 -1
- package/dist/lib/safe-json.d.ts +7 -2
- package/dist/lib/safe-json.d.ts.map +1 -1
- package/dist/lib/safe-json.js +23 -4
- package/dist/lib/safe-json.js.map +1 -1
- package/dist/lib/update-check.d.ts +17 -0
- package/dist/lib/update-check.d.ts.map +1 -0
- package/dist/lib/update-check.js +81 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/upload-limits.d.ts +17 -0
- package/dist/lib/upload-limits.d.ts.map +1 -0
- package/dist/lib/upload-limits.js +17 -0
- package/dist/lib/upload-limits.js.map +1 -0
- package/dist/lib/zip-project.d.ts +19 -0
- package/dist/lib/zip-project.d.ts.map +1 -0
- package/dist/lib/zip-project.js +39 -0
- package/dist/lib/zip-project.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +16 -0
- package/dist/version.js.map +1 -0
- package/package.json +5 -8
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { emitOk, emitErr, progress, spinnerStream } from '../output.js';
|
|
3
|
+
import { buildError } from '../errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* PINs stdout purity under --json.
|
|
6
|
+
*
|
|
7
|
+
* The contract an agent depends on is `pushto deploy --json | jq` working
|
|
8
|
+
* with no filtering, which means stdout carries EXACTLY one JSON object and
|
|
9
|
+
* nothing else. ora writes to stdout by default in every spine command, so
|
|
10
|
+
* a single un-redirected spinner frame is enough to corrupt the payload —
|
|
11
|
+
* that is what the spinnerStream assertion guards.
|
|
12
|
+
*/
|
|
13
|
+
const captureStdout = () => {
|
|
14
|
+
let buf = '';
|
|
15
|
+
const spy = vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
|
|
16
|
+
buf += String(chunk);
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
return { text: () => buf, restore: () => spy.mockRestore() };
|
|
20
|
+
};
|
|
21
|
+
const captureStderr = () => {
|
|
22
|
+
let buf = '';
|
|
23
|
+
const spy = vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
|
|
24
|
+
buf += String(chunk);
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
return { text: () => buf, restore: () => spy.mockRestore() };
|
|
28
|
+
};
|
|
29
|
+
afterEach(() => vi.restoreAllMocks());
|
|
30
|
+
describe('json mode', () => {
|
|
31
|
+
it('writes exactly one parseable object to stdout', () => {
|
|
32
|
+
const out = captureStdout();
|
|
33
|
+
emitOk({ url: 'https://x.pushto.host' }, { json: true });
|
|
34
|
+
const text = out.text();
|
|
35
|
+
out.restore();
|
|
36
|
+
expect(() => JSON.parse(text)).not.toThrow();
|
|
37
|
+
expect(JSON.parse(text)).toEqual({ ok: true, url: 'https://x.pushto.host' });
|
|
38
|
+
});
|
|
39
|
+
it('routes progress to stderr, never stdout', () => {
|
|
40
|
+
const out = captureStdout();
|
|
41
|
+
const err = captureStderr();
|
|
42
|
+
progress('zipping project...', { json: true });
|
|
43
|
+
const stdout = out.text();
|
|
44
|
+
const stderr = err.text();
|
|
45
|
+
out.restore();
|
|
46
|
+
err.restore();
|
|
47
|
+
expect(stdout).toBe('');
|
|
48
|
+
expect(stderr).toContain('zipping project');
|
|
49
|
+
});
|
|
50
|
+
it('serialises an error with its code, retryable bit and fix', () => {
|
|
51
|
+
const out = captureStdout();
|
|
52
|
+
emitErr(buildError('MISSING_ENTRYPOINT', 'no package.json in the repo root.', {
|
|
53
|
+
stage: 'build',
|
|
54
|
+
fix: { label: 'point at the subfolder', cmd: 'pushto deploy --root ./app' },
|
|
55
|
+
}), { json: true });
|
|
56
|
+
const text = out.text();
|
|
57
|
+
out.restore();
|
|
58
|
+
expect(JSON.parse(text)).toEqual({
|
|
59
|
+
ok: false,
|
|
60
|
+
stage: 'build',
|
|
61
|
+
retryable: false,
|
|
62
|
+
error: {
|
|
63
|
+
code: 'MISSING_ENTRYPOINT',
|
|
64
|
+
human: 'no package.json in the repo root.',
|
|
65
|
+
fix: { label: 'point at the subfolder', cmd: 'pushto deploy --root ./app' },
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
it('points spinners at stderr in json mode and stdout otherwise', () => {
|
|
70
|
+
expect(spinnerStream({ json: true })).toBe(process.stderr);
|
|
71
|
+
expect(spinnerStream({})).toBe(process.stdout);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('human mode', () => {
|
|
75
|
+
it('prints prose to stdout and never emits json', () => {
|
|
76
|
+
const out = captureStdout();
|
|
77
|
+
emitOk({ url: 'https://x.pushto.host', human: 'live at https://x.pushto.host' }, {});
|
|
78
|
+
const text = out.text();
|
|
79
|
+
out.restore();
|
|
80
|
+
expect(text).toContain('live at https://x.pushto.host');
|
|
81
|
+
expect(text.trim().startsWith('{')).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
it('prints the fix command under the error', () => {
|
|
84
|
+
const err = captureStderr();
|
|
85
|
+
emitErr(buildError('NO_PROJECT', 'no project here.', {
|
|
86
|
+
fix: { label: 'get started', cmd: 'pushto init <name>' },
|
|
87
|
+
}), {});
|
|
88
|
+
const text = err.text();
|
|
89
|
+
err.restore();
|
|
90
|
+
expect(text).toContain('no project here.');
|
|
91
|
+
expect(text).toContain('pushto init <name>');
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* `label: cmd` cannot express a sentence with words AFTER the command, so
|
|
95
|
+
* adopting the structured shape silently rewrote hand-written copy —
|
|
96
|
+
* "run pushto login first." became "sign in: pushto login". `prose` keeps
|
|
97
|
+
* the original sentence while agents still read label/cmd.
|
|
98
|
+
*/
|
|
99
|
+
it('reproduces hand-written prose verbatim, placing the command inline', () => {
|
|
100
|
+
const err = captureStderr();
|
|
101
|
+
emitErr(buildError('NOT_AUTHENTICATED', 'not logged in.', {
|
|
102
|
+
fix: { label: 'sign in', cmd: 'pushto login', prose: 'run {cmd} first.' },
|
|
103
|
+
}), {});
|
|
104
|
+
const text = err.text();
|
|
105
|
+
err.restore();
|
|
106
|
+
// eslint-disable-next-line no-control-regex -- strip ANSI to compare the sentence itself
|
|
107
|
+
const plain = text.replace(/\[[0-9;]*m/g, '');
|
|
108
|
+
expect(plain).toBe('> not logged in.\n run pushto login first.\n');
|
|
109
|
+
});
|
|
110
|
+
it('falls back to "label: cmd" when no prose is supplied', () => {
|
|
111
|
+
const err = captureStderr();
|
|
112
|
+
emitErr(buildError('NO_PROJECT', 'no project here.', {
|
|
113
|
+
fix: { label: 'get started', cmd: 'pushto init <name>' },
|
|
114
|
+
}), {});
|
|
115
|
+
const text = err.text();
|
|
116
|
+
err.restore();
|
|
117
|
+
// eslint-disable-next-line no-control-regex -- strip ANSI to compare the sentence itself
|
|
118
|
+
const plain = text.replace(/\[[0-9;]*m/g, '');
|
|
119
|
+
expect(plain).toBe('> no project here.\n get started: pushto init <name>\n');
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
describe('prose never reaches machine output', () => {
|
|
123
|
+
it('strips the {cmd} placeholder field from the json fix object', () => {
|
|
124
|
+
const out = captureStdout();
|
|
125
|
+
emitErr(buildError('NOT_AUTHENTICATED', 'not logged in.', {
|
|
126
|
+
stage: 'auth',
|
|
127
|
+
fix: { label: 'sign in', cmd: 'pushto login', prose: 'run {cmd} first.' },
|
|
128
|
+
}), { json: true });
|
|
129
|
+
const text = out.text();
|
|
130
|
+
out.restore();
|
|
131
|
+
expect(text).not.toContain('{cmd}');
|
|
132
|
+
expect(JSON.parse(text)).toEqual({
|
|
133
|
+
ok: false,
|
|
134
|
+
stage: 'auth',
|
|
135
|
+
retryable: false,
|
|
136
|
+
error: {
|
|
137
|
+
code: 'NOT_AUTHENTICATED',
|
|
138
|
+
human: 'not logged in.',
|
|
139
|
+
fix: { label: 'sign in', cmd: 'pushto login' },
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=output.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/output.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;GAQG;AAEH,MAAM,aAAa,GAAG,GAAgD,EAAE;IACtE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE;QACzE,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;AAC/D,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,GAAgD,EAAE;IACtE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,EAAE;QACzE,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;AAC/D,CAAC,CAAC;AAEF,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,QAAQ,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,UAAU,CAAC,oBAAoB,EAAE,mCAAmC,EAAE;YACpE,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,4BAA4B,EAAE;SAC5E,CAAC,EACF,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YAC/B,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,OAAO;YACd,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE;gBACL,IAAI,EAAE,oBAAoB;gBAC1B,KAAK,EAAE,mCAAmC;gBAC1C,GAAG,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,4BAA4B,EAAE;aAC5E;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,MAAM,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,KAAK,EAAE,+BAA+B,EAAE,EAAE,EAAE,CAAC,CAAC;QACrF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,UAAU,CAAC,YAAY,EAAE,kBAAkB,EAAE;YAC3C,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,oBAAoB,EAAE;SACzD,CAAC,EACF,EAAE,CACH,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH;;;;;OAKG;IACH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,EAAE;YAChD,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,kBAAkB,EAAE;SAC1E,CAAC,EACF,EAAE,CACH,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,yFAAyF;QACzF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,UAAU,CAAC,YAAY,EAAE,kBAAkB,EAAE;YAC3C,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,oBAAoB,EAAE;SACzD,CAAC,EACF,EAAE,CACH,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,yFAAyF;QACzF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,UAAU,CAAC,mBAAmB,EAAE,gBAAgB,EAAE;YAChD,KAAK,EAAE,MAAM;YACb,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,kBAAkB,EAAE;SAC1E,CAAC,EACF,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YAC/B,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,MAAM;YACb,SAAS,EAAE,KAAK;YAChB,KAAK,EAAE;gBACL,IAAI,EAAE,mBAAmB;gBACzB,KAAK,EAAE,gBAAgB;gBACvB,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,cAAc,EAAE;aAC/C;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-artifact.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/prepare-artifact.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { prepareArtifact } from '../prepare-artifact.js';
|
|
6
|
+
import { ARTIFACT_META_NAME } from '../build-runner.js';
|
|
7
|
+
let dir;
|
|
8
|
+
beforeEach(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pushto-prep-')); });
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
11
|
+
// Remove all exit listeners added during this test to avoid leaking listeners
|
|
12
|
+
// between tests. Vitest runs this in a worker, but exit hooks persist in the
|
|
13
|
+
// process, so we clean up to avoid interference with later tests.
|
|
14
|
+
process.removeAllListeners('exit');
|
|
15
|
+
});
|
|
16
|
+
describe('prepareArtifact', () => {
|
|
17
|
+
it('non-framework project passes through as source', async () => {
|
|
18
|
+
fs.writeFileSync(path.join(dir, 'index.html'), '<h1>hi</h1>');
|
|
19
|
+
const r = await prepareArtifact(dir, () => undefined);
|
|
20
|
+
expect(r).toEqual({ kind: 'source', zipDir: dir });
|
|
21
|
+
});
|
|
22
|
+
it('framework project builds and returns the artifact dir with the meta marker present', async () => {
|
|
23
|
+
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
|
|
24
|
+
devDependencies: { vite: '^5.0.0' },
|
|
25
|
+
scripts: { build: 'node -e "require(\'fs\').mkdirSync(\'dist\',{recursive:true});require(\'fs\').writeFileSync(\'dist/index.html\',\'built\')"' },
|
|
26
|
+
}));
|
|
27
|
+
fs.mkdirSync(path.join(dir, 'node_modules'), { recursive: true });
|
|
28
|
+
const beforeListenerCount = process.listenerCount('exit');
|
|
29
|
+
const r = await prepareArtifact(dir, () => undefined);
|
|
30
|
+
expect(r.kind).toBe('artifact');
|
|
31
|
+
if (r.kind === 'artifact') {
|
|
32
|
+
// Verify exit hook was registered
|
|
33
|
+
expect(process.listenerCount('exit')).toBe(beforeListenerCount + 1);
|
|
34
|
+
expect(r.framework).toBe('vite');
|
|
35
|
+
expect(r.zipDir).toBe(path.join(dir, 'dist'));
|
|
36
|
+
const meta = JSON.parse(fs.readFileSync(path.join(r.zipDir, ARTIFACT_META_NAME), 'utf-8'));
|
|
37
|
+
expect(meta).toMatchObject({ framework: 'vite', spa: true });
|
|
38
|
+
// Verify cleanup is idempotent — calling twice should not throw and marker should stay gone
|
|
39
|
+
r.cleanup();
|
|
40
|
+
expect(fs.existsSync(path.join(r.zipDir, ARTIFACT_META_NAME))).toBe(false);
|
|
41
|
+
r.cleanup(); // Second call should not throw
|
|
42
|
+
expect(fs.existsSync(path.join(r.zipDir, ARTIFACT_META_NAME))).toBe(false);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
it('framework project with a failing build returns failed and writes no meta', async () => {
|
|
46
|
+
fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({
|
|
47
|
+
devDependencies: { vite: '^5.0.0' },
|
|
48
|
+
scripts: { build: 'node -e "process.exit(1)"' },
|
|
49
|
+
}));
|
|
50
|
+
fs.mkdirSync(path.join(dir, 'node_modules'), { recursive: true });
|
|
51
|
+
const r = await prepareArtifact(dir, () => undefined);
|
|
52
|
+
expect(r.kind).toBe('failed');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=prepare-artifact.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-artifact.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/prepare-artifact.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-args.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/preview-args.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { resolvePreviewAction } from '../preview-args.js';
|
|
3
|
+
/**
|
|
4
|
+
* PINs for the `pushto preview` dispatcher's action grammar.
|
|
5
|
+
*
|
|
6
|
+
* docs/cli and the command's own help have taught "(create, ls, rm)" since
|
|
7
|
+
* the command shipped — but the dispatcher treated ANY unknown action word
|
|
8
|
+
* as a directory, so the documented `pushto preview create --branch x`
|
|
9
|
+
* died with "not a directory: create". The verb now exists; a positional
|
|
10
|
+
* directory still works.
|
|
11
|
+
*/
|
|
12
|
+
describe('resolvePreviewAction', () => {
|
|
13
|
+
it('bare invocation creates from the current directory', () => {
|
|
14
|
+
expect(resolvePreviewAction('', [])).toEqual({ kind: 'create', dir: '.' });
|
|
15
|
+
});
|
|
16
|
+
it('the documented `create` verb creates from the current directory', () => {
|
|
17
|
+
expect(resolvePreviewAction('create', [])).toEqual({ kind: 'create', dir: '.' });
|
|
18
|
+
});
|
|
19
|
+
it('`create <dir>` targets that directory', () => {
|
|
20
|
+
expect(resolvePreviewAction('create', ['dist'])).toEqual({ kind: 'create', dir: 'dist' });
|
|
21
|
+
});
|
|
22
|
+
it('a bare positional directory still works (pushto preview dist)', () => {
|
|
23
|
+
expect(resolvePreviewAction('dist', [])).toEqual({ kind: 'create', dir: 'dist' });
|
|
24
|
+
});
|
|
25
|
+
it('ls and list both list', () => {
|
|
26
|
+
expect(resolvePreviewAction('ls', [])).toEqual({ kind: 'ls' });
|
|
27
|
+
expect(resolvePreviewAction('list', [])).toEqual({ kind: 'ls' });
|
|
28
|
+
});
|
|
29
|
+
it('rm and delete both remove, carrying the ref', () => {
|
|
30
|
+
expect(resolvePreviewAction('rm', ['feature-x'])).toEqual({ kind: 'rm', ref: 'feature-x' });
|
|
31
|
+
expect(resolvePreviewAction('delete', ['abc123'])).toEqual({ kind: 'rm', ref: 'abc123' });
|
|
32
|
+
});
|
|
33
|
+
it('rm without a ref reports the miss instead of guessing', () => {
|
|
34
|
+
expect(resolvePreviewAction('rm', [])).toEqual({ kind: 'rm', ref: undefined });
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=preview-args.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-args.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/preview-args.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;;;;GAQG;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,oBAAoB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5F,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/lib/api.d.ts
CHANGED
package/dist/lib/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAgEA,eAAO,MAAM,GAAG,GAAU,MAAM,MAAM,EAAE,UAAS,WAAgB,KAAG,OAAO,CAAC,QAAQ,CA4BnF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,YAAY,QAAO,WAAqD,CAAC"}
|
package/dist/lib/api.js
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
-
import { config, getToken, getRefreshToken, setToken, isTokenExpired } from './config.js';
|
|
1
|
+
import { config, getToken, getRefreshToken, setToken, clearToken, isTokenExpired } from './config.js';
|
|
2
|
+
/** Default timeout for API requests (30 seconds) */
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
/** Extended timeout for upload/deploy operations (10 minutes).
|
|
5
|
+
* Matches the web route's MAX_WAIT poll budget so the CLI doesn't abort
|
|
6
|
+
* with `network error` while the server is still legitimately polling
|
|
7
|
+
* the deploy-agent for a slow first build (Rust workspace, large
|
|
8
|
+
* Next.js app). When the server times out, it returns 504 with
|
|
9
|
+
* `stillBuilding: true` and the CLI shows a "still building" message. */
|
|
10
|
+
const DEPLOY_TIMEOUT_MS = 600_000;
|
|
11
|
+
/** Timeout for token refresh requests (10 seconds) */
|
|
12
|
+
const REFRESH_TIMEOUT_MS = 10_000;
|
|
2
13
|
/**
|
|
3
14
|
* Auto-refresh the Supabase access token if it's expired.
|
|
4
15
|
* Uses the stored refresh token to get a new access token silently.
|
|
@@ -8,23 +19,39 @@ const ensureFreshToken = async () => {
|
|
|
8
19
|
return;
|
|
9
20
|
const refreshToken = getRefreshToken();
|
|
10
21
|
if (!refreshToken)
|
|
11
|
-
return;
|
|
22
|
+
return;
|
|
12
23
|
const baseUrl = config.get('apiUrl');
|
|
13
24
|
try {
|
|
14
25
|
const res = await fetch(`${baseUrl}/api/cli/refresh`, {
|
|
15
26
|
method: 'POST',
|
|
16
27
|
headers: { 'Content-Type': 'application/json' },
|
|
17
28
|
body: JSON.stringify({ refreshToken }),
|
|
29
|
+
signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
|
|
18
30
|
});
|
|
31
|
+
if (res.status === 401 || res.status === 403) {
|
|
32
|
+
// Refresh token is expired/revoked — clear credentials AND tell the
|
|
33
|
+
// user exactly what to do. Without this hint, the upcoming API call
|
|
34
|
+
// returns a generic "not authenticated" and the user has no idea
|
|
35
|
+
// their multi-week session just rolled off — they assume their
|
|
36
|
+
// login is broken or pushto is broken.
|
|
37
|
+
//
|
|
38
|
+
// Stderr keeps the message out of any captured stdout (e.g. when
|
|
39
|
+
// the user pipes `pushto env list | grep ...` and we don't want to
|
|
40
|
+
// pollute the pipe). Plain text — no chalk import here to keep this
|
|
41
|
+
// module dependency-free for the auth-bootstrap path.
|
|
42
|
+
clearToken();
|
|
43
|
+
process.stderr.write('your pushto session expired. run `pushto login` to sign back in.\n');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
19
46
|
if (!res.ok)
|
|
20
|
-
return;
|
|
47
|
+
return;
|
|
21
48
|
const data = (await res.json());
|
|
22
49
|
if (data.access_token) {
|
|
23
50
|
setToken(data.access_token, data.refresh_token);
|
|
24
51
|
}
|
|
25
52
|
}
|
|
26
53
|
catch {
|
|
27
|
-
//
|
|
54
|
+
// Network error or timeout — next API call will get 401 and user will re-login
|
|
28
55
|
}
|
|
29
56
|
};
|
|
30
57
|
export const api = async (path, options = {}) => {
|
|
@@ -36,7 +63,10 @@ export const api = async (path, options = {}) => {
|
|
|
36
63
|
const headers = {
|
|
37
64
|
...existingHeaders,
|
|
38
65
|
};
|
|
39
|
-
|
|
66
|
+
// Skip Content-Type for FormData — fetch needs to generate its own
|
|
67
|
+
// multipart/form-data boundary, which it only does when Content-Type is unset.
|
|
68
|
+
const isFormData = typeof FormData !== 'undefined' && options.body instanceof FormData;
|
|
69
|
+
if (!headers['Content-Type'] && !isFormData) {
|
|
40
70
|
headers['Content-Type'] = 'application/json';
|
|
41
71
|
}
|
|
42
72
|
if (token) {
|
|
@@ -45,6 +75,9 @@ export const api = async (path, options = {}) => {
|
|
|
45
75
|
return fetch(`${baseUrl}/api${path}`, {
|
|
46
76
|
...options,
|
|
47
77
|
headers,
|
|
78
|
+
signal: options.signal ?? AbortSignal.timeout(DEFAULT_TIMEOUT_MS),
|
|
48
79
|
});
|
|
49
80
|
};
|
|
81
|
+
/** Create an AbortSignal with extended timeout for upload/deploy operations. */
|
|
82
|
+
export const deploySignal = () => AbortSignal.timeout(DEPLOY_TIMEOUT_MS);
|
|
50
83
|
//# sourceMappingURL=api.js.map
|
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The only readline interface in the CLI.
|
|
3
|
+
*
|
|
4
|
+
* Callers MUST gate this behind canPrompt() from ./interactive.js. It lives
|
|
5
|
+
* here rather than in a command so the guard
|
|
6
|
+
* (apps/web/scripts/guard-cli-interactive.mjs) can prove no command reaches
|
|
7
|
+
* for stdin on its own — which is exactly how the deploy hang happened.
|
|
8
|
+
*
|
|
9
|
+
* Note what this cannot do: readline's question callback never fires on EOF,
|
|
10
|
+
* so with stdin closed the returned promise never settles. There is no
|
|
11
|
+
* timeout and no rejection to catch. That is not a bug to fix here; it is
|
|
12
|
+
* why the decision to call this at all belongs to canPrompt().
|
|
13
|
+
*/
|
|
14
|
+
export declare const ask: (question: string) => Promise<string>;
|
|
15
|
+
//# sourceMappingURL=ask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/lib/ask.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG,GAAI,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAQpD,CAAC"}
|
package/dist/lib/ask.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createInterface } from 'node:readline';
|
|
2
|
+
/**
|
|
3
|
+
* The only readline interface in the CLI.
|
|
4
|
+
*
|
|
5
|
+
* Callers MUST gate this behind canPrompt() from ./interactive.js. It lives
|
|
6
|
+
* here rather than in a command so the guard
|
|
7
|
+
* (apps/web/scripts/guard-cli-interactive.mjs) can prove no command reaches
|
|
8
|
+
* for stdin on its own — which is exactly how the deploy hang happened.
|
|
9
|
+
*
|
|
10
|
+
* Note what this cannot do: readline's question callback never fires on EOF,
|
|
11
|
+
* so with stdin closed the returned promise never settles. There is no
|
|
12
|
+
* timeout and no rejection to catch. That is not a bug to fix here; it is
|
|
13
|
+
* why the decision to call this at all belongs to canPrompt().
|
|
14
|
+
*/
|
|
15
|
+
export const ask = (question) => {
|
|
16
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
rl.question(question, (answer) => {
|
|
19
|
+
rl.close();
|
|
20
|
+
resolve(answer.trim());
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=ask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/lib/ask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,QAAgB,EAAmB,EAAE;IACvD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { StaticFrameworkDetection } from './detect-static-framework.js';
|
|
2
|
+
/**
|
|
3
|
+
* Runs a static-output framework build on the user's machine and resolves
|
|
4
|
+
* where the artifact landed. Every failure returns { ok: false } with the
|
|
5
|
+
* captured output — the caller never uploads on failure, and never falls
|
|
6
|
+
* back to stale output (honest failure beats stale success).
|
|
7
|
+
*/
|
|
8
|
+
export declare const ARTIFACT_META_NAME = "_pushto_meta.json";
|
|
9
|
+
export type BuildOutcome = {
|
|
10
|
+
ok: true;
|
|
11
|
+
outputDir: string;
|
|
12
|
+
typeWarnings: string | null;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
message: string;
|
|
16
|
+
buildOutput: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const runStaticBuild: (dir: string, detection: StaticFrameworkDetection, opts?: {
|
|
19
|
+
log?: (line: string) => void;
|
|
20
|
+
}) => Promise<BuildOutcome>;
|
|
21
|
+
export declare const writeArtifactMeta: (outputDir: string, meta: {
|
|
22
|
+
framework: string;
|
|
23
|
+
spa: boolean;
|
|
24
|
+
}) => (() => void);
|
|
25
|
+
//# sourceMappingURL=build-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-runner.d.ts","sourceRoot":"","sources":["../../src/lib/build-runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE7E;;;;;GAKG;AAEH,eAAO,MAAM,kBAAkB,sBAAsB,CAAC;AAUtD,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC5D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAyExD,eAAO,MAAM,cAAc,GACzB,KAAK,MAAM,EACX,WAAW,wBAAwB,EACnC,OAAO;IAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,KACtC,OAAO,CAAC,YAAY,CA0DtB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,MAAM;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,KACxC,CAAC,MAAM,IAAI,CAMb,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Runs a static-output framework build on the user's machine and resolves
|
|
6
|
+
* where the artifact landed. Every failure returns { ok: false } with the
|
|
7
|
+
* captured output — the caller never uploads on failure, and never falls
|
|
8
|
+
* back to stale output (honest failure beats stale success).
|
|
9
|
+
*/
|
|
10
|
+
export const ARTIFACT_META_NAME = '_pushto_meta.json';
|
|
11
|
+
const BUILD_TIMEOUT_MS = 10 * 60 * 1000; // generous: old laptops, cold gatsby
|
|
12
|
+
const FALLBACK_SCAN_DIRS = ['dist', 'build', 'out', '_site'];
|
|
13
|
+
/** The stock Vite React-TS scaffold build script. Only this exact shape
|
|
14
|
+
* earns the tsc-fallback retry (Scott's call, spec decision #4): any
|
|
15
|
+
* customized script is the user's contract and fails honestly. */
|
|
16
|
+
const STOCK_TSC_VITE = /^\s*tsc(?:\s+-b)?\s*&&\s*vite\s+build\s*$/;
|
|
17
|
+
const detectPm = (dir) => {
|
|
18
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml')))
|
|
19
|
+
return 'pnpm';
|
|
20
|
+
if (fs.existsSync(path.join(dir, 'yarn.lock')))
|
|
21
|
+
return 'yarn';
|
|
22
|
+
return 'npm';
|
|
23
|
+
};
|
|
24
|
+
const exec = (cmd, cwd) => new Promise((resolve) => {
|
|
25
|
+
const [bin, ...args] = cmd;
|
|
26
|
+
const child = spawn(bin, args, {
|
|
27
|
+
cwd,
|
|
28
|
+
// Windows needs a shell to resolve npm.cmd / pnpm.cmd shims.
|
|
29
|
+
shell: process.platform === 'win32',
|
|
30
|
+
});
|
|
31
|
+
const chunks = [];
|
|
32
|
+
child.stdout.on('data', (d) => chunks.push(d.toString()));
|
|
33
|
+
child.stderr.on('data', (d) => chunks.push(d.toString()));
|
|
34
|
+
const timer = setTimeout(() => {
|
|
35
|
+
child.kill('SIGKILL');
|
|
36
|
+
chunks.push('\n(build timed out after 10 minutes)');
|
|
37
|
+
}, BUILD_TIMEOUT_MS);
|
|
38
|
+
child.on('close', (code) => {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
resolve({ code: code ?? 1, output: chunks.join('') });
|
|
41
|
+
});
|
|
42
|
+
child.on('error', (err) => {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
resolve({ code: 1, output: String(err) });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
const installCmd = (pm) => pm === 'pnpm' ? ['pnpm', 'install'] : pm === 'yarn' ? ['yarn', 'install'] : ['npm', 'install'];
|
|
48
|
+
const runScriptCmd = (pm, script) => pm === 'pnpm' ? ['pnpm', 'run', script] : pm === 'yarn' ? ['yarn', 'run', script] : ['npm', 'run', script];
|
|
49
|
+
/** Run a local bin directly (the tsc-fallback retry). */
|
|
50
|
+
const execLocalBinCmd = (pm, bin, args) => pm === 'pnpm' ? ['pnpm', 'exec', bin, ...args]
|
|
51
|
+
: pm === 'yarn' ? ['yarn', bin, ...args]
|
|
52
|
+
: ['npx', '--no-install', bin, ...args];
|
|
53
|
+
/** First candidate dir containing an index.html written after buildStart. */
|
|
54
|
+
const resolveOutputDir = (dir, candidates, buildStart) => {
|
|
55
|
+
const all = [...candidates, ...FALLBACK_SCAN_DIRS.filter((d) => !candidates.includes(d))];
|
|
56
|
+
for (const c of all) {
|
|
57
|
+
const indexPath = path.join(dir, c, 'index.html');
|
|
58
|
+
try {
|
|
59
|
+
const stat = fs.statSync(indexPath);
|
|
60
|
+
if (stat.mtimeMs >= buildStart)
|
|
61
|
+
return path.join(dir, c);
|
|
62
|
+
}
|
|
63
|
+
catch { /* not there — next candidate */ }
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
};
|
|
67
|
+
/** The real build command per framework — the message must name a fix
|
|
68
|
+
* that actually works when pasted into package.json. */
|
|
69
|
+
const BUILD_SCRIPT_SUGGESTION = {
|
|
70
|
+
vite: 'vite build',
|
|
71
|
+
astro: 'astro build',
|
|
72
|
+
gatsby: 'gatsby build',
|
|
73
|
+
angular: 'ng build',
|
|
74
|
+
cra: 'react-scripts build',
|
|
75
|
+
eleventy: 'eleventy',
|
|
76
|
+
};
|
|
77
|
+
export const runStaticBuild = async (dir, detection, opts) => {
|
|
78
|
+
const log = opts?.log ?? (() => undefined);
|
|
79
|
+
const pm = detectPm(dir);
|
|
80
|
+
const pkgRaw = fs.readFileSync(path.join(dir, 'package.json'), 'utf-8');
|
|
81
|
+
// JSON.parse returns any; scripts is optional-chained below, so an
|
|
82
|
+
// unexpected shape yields undefined rather than a crash.
|
|
83
|
+
const pkg = JSON.parse(pkgRaw);
|
|
84
|
+
const buildScript = pkg.scripts?.build;
|
|
85
|
+
if (!buildScript) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
buildOutput: '',
|
|
89
|
+
message: `your package.json has no build script. ${detection.framework} projects need one. add "build": "${BUILD_SCRIPT_SUGGESTION[detection.framework]}" and run pushto again.`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (!fs.existsSync(path.join(dir, 'node_modules'))) {
|
|
93
|
+
log(`installing dependencies (${pm})...`);
|
|
94
|
+
const install = await exec(installCmd(pm), dir);
|
|
95
|
+
if (install.code !== 0) {
|
|
96
|
+
return { ok: false, message: 'dependency install failed. run the install yourself to see the full story, then pushto again.', buildOutput: install.output };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const buildStart = Date.now();
|
|
100
|
+
log(`building (${detection.framework})...`);
|
|
101
|
+
const build = await exec(runScriptCmd(pm, 'build'), dir);
|
|
102
|
+
let typeWarnings = null;
|
|
103
|
+
if (build.code !== 0) {
|
|
104
|
+
// Stock-scaffold typecheck fallback: dev mode never typechecks, so
|
|
105
|
+
// AI-scaffolded apps that work in dev routinely die here on type
|
|
106
|
+
// errors. For the EXACT stock script shape only, retry vite alone,
|
|
107
|
+
// ship, and surface the type errors as a warning.
|
|
108
|
+
if (detection.framework === 'vite' && STOCK_TSC_VITE.test(buildScript)) {
|
|
109
|
+
log('type errors found. retrying with vite alone...');
|
|
110
|
+
const retry = await exec(execLocalBinCmd(pm, 'vite', ['build']), dir);
|
|
111
|
+
if (retry.code !== 0) {
|
|
112
|
+
return { ok: false, message: 'the build failed. the output below is the real story. fix it, or run the build yourself to iterate faster.', buildOutput: retry.output };
|
|
113
|
+
}
|
|
114
|
+
typeWarnings = build.output;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return { ok: false, message: 'the build failed. the output below is the real story. fix it, or run the build yourself to iterate faster.', buildOutput: build.output };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const outputDir = resolveOutputDir(dir, detection.outputDirs, buildStart);
|
|
121
|
+
if (!outputDir) {
|
|
122
|
+
const looked = [...detection.outputDirs, ...FALLBACK_SCAN_DIRS].join(', ');
|
|
123
|
+
return {
|
|
124
|
+
ok: false,
|
|
125
|
+
buildOutput: build.output,
|
|
126
|
+
message: `the build finished but produced no fresh index.html. looked in: ${looked}. if your build outputs somewhere else, point it at one of those. server-rendered setups need the container path instead.`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return { ok: true, outputDir, typeWarnings };
|
|
130
|
+
};
|
|
131
|
+
export const writeArtifactMeta = (outputDir, meta) => {
|
|
132
|
+
const metaPath = path.join(outputDir, ARTIFACT_META_NAME);
|
|
133
|
+
fs.writeFileSync(metaPath, JSON.stringify({ ...meta, generator: 'pushto-cli' }));
|
|
134
|
+
return () => {
|
|
135
|
+
try {
|
|
136
|
+
fs.rmSync(metaPath, { force: true });
|
|
137
|
+
}
|
|
138
|
+
catch { /* best effort */ }
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=build-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-runner.js","sourceRoot":"","sources":["../../src/lib/build-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ interface PushtoConfig {
|
|
|
6
6
|
projectSlug?: string;
|
|
7
7
|
}
|
|
8
8
|
export declare const config: Conf<PushtoConfig>;
|
|
9
|
+
/**
|
|
10
|
+
* PUSHTO_TOKEN wins over stored config so a headless caller never has to run
|
|
11
|
+
* the browser login flow. An empty value is treated as unset, so
|
|
12
|
+
* `PUSHTO_TOKEN= pushto deploy` falls back rather than authenticating as "".
|
|
13
|
+
* This is also the bootstrap path for MCP auth, which expects a bearer token.
|
|
14
|
+
*/
|
|
9
15
|
export declare const getToken: () => string | undefined;
|
|
10
16
|
export declare const getRefreshToken: () => string | undefined;
|
|
11
17
|
export declare const setToken: (token: string, refreshToken?: string) => void;
|