@percher/core 0.4.13 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy-repo.d.ts +28 -0
- package/dist/commands/deploy-repo.d.ts.map +1 -0
- package/dist/commands/deploy-repo.js +265 -0
- package/dist/commands/deploy-repo.js.map +1 -0
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -32
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts +37 -5
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +39 -6
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/publish-from-repo.d.ts +22 -0
- package/dist/commands/publish-from-repo.d.ts.map +1 -0
- package/dist/commands/publish-from-repo.js +236 -0
- package/dist/commands/publish-from-repo.js.map +1 -0
- package/dist/commands/publish-inline.d.ts +32 -0
- package/dist/commands/publish-inline.d.ts.map +1 -0
- package/dist/commands/publish-inline.js +339 -0
- package/dist/commands/publish-inline.js.map +1 -0
- package/dist/commands/publish.d.ts +63 -0
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +34 -4
- package/dist/commands/publish.js.map +1 -1
- package/dist/detect.d.ts +19 -0
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +128 -39
- package/dist/detect.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/static-docker.d.ts.map +1 -1
- package/dist/static-docker.js +2 -1
- package/dist/static-docker.js.map +1 -1
- package/dist/tarball.d.ts +39 -1
- package/dist/tarball.d.ts.map +1 -1
- package/dist/tarball.js +92 -16
- package/dist/tarball.js.map +1 -1
- package/dist/templates.d.ts +6 -0
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +8 -0
- package/dist/templates.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { PercherApiError } from "@percher/client";
|
|
2
|
+
import { TIMEOUTS } from "@percher/shared/timeouts";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { pollDeployment } from "../poll-deployment.js";
|
|
5
|
+
import { RECOVERY_NEEDS_LOGIN, RECOVERY_NONE, recoveryAsk, recoveryWait } from "../recovery.js";
|
|
6
|
+
import { classifyDeploymentFailure } from "./publish-failure.js";
|
|
7
|
+
export const publishFromRepoInputSchema = z.object({
|
|
8
|
+
url: z
|
|
9
|
+
.string()
|
|
10
|
+
.min(1)
|
|
11
|
+
.describe("Public https git repo URL to clone and deploy (one-shot — no webhook is created)."),
|
|
12
|
+
name: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("App name. Overrides the repo's percher.toml [app].name; required if the repo omits it."),
|
|
16
|
+
branch: z.string().optional().describe("Branch to deploy. Defaults to main."),
|
|
17
|
+
note: z.string().optional().describe("Optional note recorded against the deploy."),
|
|
18
|
+
waitForLive: z
|
|
19
|
+
.boolean()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("If false (default on the hosted connector), returns once the deploy is queued — resume with percher_wait_for_deploy. If true, block until live or failed."),
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Hosted "publish from a public repo URL" — one-shot clone + deploy of a PUBLIC
|
|
25
|
+
* repo, the URL counterpart to `publishInline`. The server clones the tracked
|
|
26
|
+
* branch HEAD once, reads the repo's percher.toml for the app name + runtime,
|
|
27
|
+
* creates-or-gets the app, and deploys — no persistent connection/webhook is
|
|
28
|
+
* set up (that stays the owner-only `import/*` path). Returns the same
|
|
29
|
+
* PublishResult shape + recovery contract as `publishInline` / `deployRepo`, so
|
|
30
|
+
* the `wait_deploy` chain works identically.
|
|
31
|
+
*/
|
|
32
|
+
export async function publishFromRepo(ctx, input) {
|
|
33
|
+
const t0 = Date.now();
|
|
34
|
+
ctx.status(`Cloning ${input.url} ...`);
|
|
35
|
+
let initial;
|
|
36
|
+
try {
|
|
37
|
+
initial = await ctx.client.apps.publishFromGit({
|
|
38
|
+
url: input.url,
|
|
39
|
+
...(input.name ? { name: input.name } : {}),
|
|
40
|
+
...(input.branch ? { branch: input.branch } : {}),
|
|
41
|
+
...(input.note ? { note: input.note } : {}),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err instanceof PercherApiError) {
|
|
46
|
+
if (err.status === 401) {
|
|
47
|
+
return {
|
|
48
|
+
status: "needs_login",
|
|
49
|
+
fileCount: 0,
|
|
50
|
+
bytes: 0,
|
|
51
|
+
recovery: RECOVERY_NEEDS_LOGIN,
|
|
52
|
+
summary: "Not logged in — run `bunx percher login` first.",
|
|
53
|
+
configPath: "",
|
|
54
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Per-user clone rate limit (publish-from-repo.ts) — retryable.
|
|
58
|
+
if (err.status === 429) {
|
|
59
|
+
const retryAfterSec = err.extra?.retryAfterSec ?? 60;
|
|
60
|
+
return {
|
|
61
|
+
status: "failed",
|
|
62
|
+
fileCount: 0,
|
|
63
|
+
bytes: 0,
|
|
64
|
+
error: {
|
|
65
|
+
title: "Repo-publish rate limit reached",
|
|
66
|
+
explanation: err.message,
|
|
67
|
+
suggestion: `Wait ${retryAfterSec}s and try again — this is a short-window per-account limit.`,
|
|
68
|
+
},
|
|
69
|
+
recovery: recoveryAsk({
|
|
70
|
+
prompt: `Repo-publish rate limit reached. Wait ${retryAfterSec}s and try again.`,
|
|
71
|
+
reasonCode: "infra_transient",
|
|
72
|
+
retryable: true,
|
|
73
|
+
}),
|
|
74
|
+
summary: `Repo-publish rate limit hit. Retry in ${retryAfterSec}s.`,
|
|
75
|
+
configPath: "",
|
|
76
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
switch (err.code) {
|
|
80
|
+
case "INVALID_REPO_URL":
|
|
81
|
+
case "DNS_DRIFT":
|
|
82
|
+
case "CLONE_FAILED":
|
|
83
|
+
case "CLONE_TIMEOUT":
|
|
84
|
+
case "IMPORT_TOO_LARGE":
|
|
85
|
+
case "TARBALL_FAILED":
|
|
86
|
+
case "REPO_MISSING_CONFIG":
|
|
87
|
+
case "REPO_INVALID_CONFIG":
|
|
88
|
+
case "NAME_BLOCKED":
|
|
89
|
+
case "VALIDATION_ERROR":
|
|
90
|
+
case "APP_LIMIT_REACHED":
|
|
91
|
+
case "ACCOUNT_SUSPENDED":
|
|
92
|
+
case "APP_SUSPENDED":
|
|
93
|
+
case "EMAIL_NOT_VERIFIED":
|
|
94
|
+
return failureResult({
|
|
95
|
+
title: err.message,
|
|
96
|
+
explanation: err.message,
|
|
97
|
+
suggestion: "Fix the issue described above (repo URL / percher.toml / plan limit), then re-run. Surface this to the user.",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
// Fetch the (possibly newly-created) app for the live URL + result shape.
|
|
104
|
+
// Best-effort: fall back to a minimal app synthesized from the deployment.
|
|
105
|
+
let app;
|
|
106
|
+
try {
|
|
107
|
+
app = await ctx.client.apps.get(initial.appId);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
app = {
|
|
111
|
+
id: initial.appId,
|
|
112
|
+
name: input.name ?? initial.appId,
|
|
113
|
+
url: initial.url ?? `https://${input.name ?? initial.appId}.percher.run`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Async opt-in: hand control back as soon as the deploy is queued so the
|
|
117
|
+
// agent can resume with percher_wait_for_deploy instead of blocking on the
|
|
118
|
+
// build. (The clone already happened server-side during publishFromGit.)
|
|
119
|
+
if (input.waitForLive === false) {
|
|
120
|
+
return {
|
|
121
|
+
status: "queued",
|
|
122
|
+
app,
|
|
123
|
+
deployment: initial,
|
|
124
|
+
fileCount: 0,
|
|
125
|
+
bytes: 0,
|
|
126
|
+
recovery: recoveryWait({
|
|
127
|
+
app: app.name,
|
|
128
|
+
deployId: initial.id,
|
|
129
|
+
reasonCode: "deploy_queued",
|
|
130
|
+
}),
|
|
131
|
+
summary: `${app.name} deploy ${initial.id} queued (cloned ${input.url}) — resume with percher_wait_for_deploy.`,
|
|
132
|
+
configPath: "",
|
|
133
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Synchronous: poll the new deployment to terminal status (mirror deployRepo).
|
|
137
|
+
const buildStart = Date.now();
|
|
138
|
+
const timeoutMs = TIMEOUTS.clientPublishPoll;
|
|
139
|
+
let lastStatus;
|
|
140
|
+
let nextHeartbeatMs = 15_000;
|
|
141
|
+
let deployment = initial;
|
|
142
|
+
let timedOut = null;
|
|
143
|
+
try {
|
|
144
|
+
deployment = await pollDeployment({
|
|
145
|
+
ctx,
|
|
146
|
+
appId: app.id,
|
|
147
|
+
initial,
|
|
148
|
+
intervalMs: 2000,
|
|
149
|
+
timeoutMs,
|
|
150
|
+
appName: app.name,
|
|
151
|
+
onTick: (d) => {
|
|
152
|
+
const elapsedMs = Date.now() - buildStart;
|
|
153
|
+
if (d.status !== lastStatus) {
|
|
154
|
+
ctx.status(`${d.status}...`);
|
|
155
|
+
lastStatus = d.status;
|
|
156
|
+
nextHeartbeatMs = elapsedMs + 15_000;
|
|
157
|
+
}
|
|
158
|
+
else if (elapsedMs >= nextHeartbeatMs) {
|
|
159
|
+
ctx.status(`${d.status}... (${Math.round(elapsedMs / 1000)}s elapsed)`);
|
|
160
|
+
nextHeartbeatMs = elapsedMs + 15_000;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
onTimeout: (d) => {
|
|
164
|
+
timedOut = { deployment: d };
|
|
165
|
+
throw new (class PollTimeoutSentinel extends Error {
|
|
166
|
+
})("__poll_timeout__");
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (!timedOut) {
|
|
172
|
+
return failureResult({
|
|
173
|
+
title: "Deploy did not complete",
|
|
174
|
+
explanation: err instanceof Error
|
|
175
|
+
? err.message
|
|
176
|
+
: "The deploy stopped responding before reaching a terminal state.",
|
|
177
|
+
suggestion: `Inspect with \`bunx percher deploys inspect ${initial.id}\`.`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (timedOut) {
|
|
182
|
+
const stuck = timedOut.deployment;
|
|
183
|
+
return failureResult({
|
|
184
|
+
title: "Deploy timed out",
|
|
185
|
+
explanation: "The deploy did not complete within 5 minutes.",
|
|
186
|
+
suggestion: `Inspect with \`bunx percher deploys inspect ${stuck.id}\`.`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const totalSeconds = (Date.now() - t0) / 1000;
|
|
190
|
+
const url = deployment.previewUrl ?? deployment.url ?? app.url;
|
|
191
|
+
if (deployment.status === "failed") {
|
|
192
|
+
const { error, recovery, summary } = await classifyDeploymentFailure({ ctx, app, deployment });
|
|
193
|
+
return {
|
|
194
|
+
status: "failed",
|
|
195
|
+
app,
|
|
196
|
+
deployment,
|
|
197
|
+
fileCount: 0,
|
|
198
|
+
bytes: 0,
|
|
199
|
+
error,
|
|
200
|
+
recovery,
|
|
201
|
+
summary,
|
|
202
|
+
configPath: "",
|
|
203
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
ctx.status(`Live at ${url} (${totalSeconds.toFixed(0)}s)`);
|
|
207
|
+
return {
|
|
208
|
+
status: "live",
|
|
209
|
+
app,
|
|
210
|
+
deployment,
|
|
211
|
+
url,
|
|
212
|
+
timing: { totalSeconds, packageMs: 0, uploadMs: 0, buildMs: Date.now() - buildStart },
|
|
213
|
+
fileCount: 0,
|
|
214
|
+
bytes: 0,
|
|
215
|
+
recovery: RECOVERY_NONE,
|
|
216
|
+
summary: `${app.name} deployed from ${input.url} (${totalSeconds.toFixed(0)}s) → ${url}`,
|
|
217
|
+
configPath: "",
|
|
218
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function failureResult(error) {
|
|
222
|
+
return {
|
|
223
|
+
status: "failed",
|
|
224
|
+
fileCount: 0,
|
|
225
|
+
bytes: 0,
|
|
226
|
+
error,
|
|
227
|
+
recovery: recoveryAsk({
|
|
228
|
+
prompt: `${error.title}: ${error.explanation} ${error.suggestion}`.trim(),
|
|
229
|
+
reasonCode: "unknown",
|
|
230
|
+
}),
|
|
231
|
+
summary: error.title,
|
|
232
|
+
configPath: "",
|
|
233
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=publish-from-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-from-repo.js","sourceRoot":"","sources":["../../src/commands/publish-from-repo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Context } from "../context.js";
|
|
3
|
+
import { type PublishResult } from "./publish.js";
|
|
4
|
+
export declare const publishInlineInputSchema: z.ZodObject<{
|
|
5
|
+
name: z.ZodOptional<z.ZodString>;
|
|
6
|
+
files: z.ZodArray<z.ZodObject<{
|
|
7
|
+
path: z.ZodString;
|
|
8
|
+
content: z.ZodString;
|
|
9
|
+
encoding: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
base64: "base64";
|
|
11
|
+
utf8: "utf8";
|
|
12
|
+
}>>;
|
|
13
|
+
}, z.core.$strip>>;
|
|
14
|
+
preview: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
message: z.ZodOptional<z.ZodString>;
|
|
16
|
+
noCache: z.ZodOptional<z.ZodBoolean>;
|
|
17
|
+
waitForLive: z.ZodOptional<z.ZodBoolean>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
export type PublishInlineInput = z.infer<typeof publishInlineInputSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Hosted "publish from inline source" — the filesystem-free counterpart
|
|
22
|
+
* to {@link publish}. An assistant passes the source files it just
|
|
23
|
+
* generated (including a `percher.toml`) as a tool argument; this builds
|
|
24
|
+
* a tarball entirely in memory and ships it through the curated
|
|
25
|
+
* `POST /apps/publish` endpoint (the only publish surface an OAuth token
|
|
26
|
+
* may reach). It NEVER reads `ctx.cwd`.
|
|
27
|
+
*
|
|
28
|
+
* Returns the same {@link PublishResult} shape + recovery contract as
|
|
29
|
+
* `publish` so an agent's `wait_for_deploy` chain works identically.
|
|
30
|
+
*/
|
|
31
|
+
export declare function publishInline(ctx: Context, input: PublishInlineInput): Promise<PublishResult>;
|
|
32
|
+
//# sourceMappingURL=publish-inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-inline.d.ts","sourceRoot":"","sources":["../../src/commands/publish-inline.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAW1C,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/D,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;iBAwCnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AA0B1E;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,aAAa,CAAC,CA6BxB"}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { isDeployAlreadyInProgress, PercherApiError } from "@percher/client";
|
|
2
|
+
import { MAX_INLINE_PUBLISH_BYTES } from "@percher/shared";
|
|
3
|
+
import { PercherTomlError, parse, serialize } from "@percher/toml";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { configFromDetection, detectFrameworkFromFiles } from "../detect.js";
|
|
6
|
+
import { recoveryAsk, recoveryFixConfig, recoveryWait, } from "../recovery.js";
|
|
7
|
+
import { createTarballFromFiles } from "../tarball.js";
|
|
8
|
+
import { tomlErrorToRecoveryProblems } from "../toml-recovery.js";
|
|
9
|
+
import { finalizeDeploy } from "./publish.js";
|
|
10
|
+
import { classifyPublishApiError, DEPLOY_GATE_CODES } from "./publish-api-error.js";
|
|
11
|
+
export const publishInlineInputSchema = z.object({
|
|
12
|
+
name: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("App name. Overrides [app].name when percher.toml is present; REQUIRED when no percher.toml is provided (so the auto-detected app can be named)."),
|
|
16
|
+
files: z
|
|
17
|
+
.array(z.object({
|
|
18
|
+
path: z.string().min(1).describe("Repo-relative path (no leading / and no ..)."),
|
|
19
|
+
content: z
|
|
20
|
+
.string()
|
|
21
|
+
.describe("File contents — UTF-8 text, or base64-encoded bytes when encoding is 'base64'."),
|
|
22
|
+
encoding: z
|
|
23
|
+
.enum(["utf8", "base64"])
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Content encoding. Default 'utf8' (text). Use 'base64' for binary assets (images, fonts)."),
|
|
26
|
+
}))
|
|
27
|
+
.min(1)
|
|
28
|
+
.describe("Inline source files. Include a percher.toml ([app].name + runtime), or omit it and Percher auto-detects the runtime from the files (then `name` is required)."),
|
|
29
|
+
preview: z
|
|
30
|
+
.boolean()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Deploy as a preview (does not replace the live version)."),
|
|
33
|
+
message: z.string().optional().describe("Deploy note (visible in deploy history)."),
|
|
34
|
+
noCache: z.boolean().optional().describe("Skip the image cache and force a fresh build."),
|
|
35
|
+
waitForLive: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("If true (default), block until the deploy is live or failed. If false, return as soon as it is queued so the agent can resume with percher_wait_for_deploy."),
|
|
39
|
+
});
|
|
40
|
+
const TOML_FILENAME = "percher.toml";
|
|
41
|
+
/** Decode an inline file's `content` to raw bytes (utf8 text or base64). */
|
|
42
|
+
function fileBytes(f) {
|
|
43
|
+
return f.encoding === "base64"
|
|
44
|
+
? new Uint8Array(Buffer.from(f.content, "base64"))
|
|
45
|
+
: new TextEncoder().encode(f.content);
|
|
46
|
+
}
|
|
47
|
+
/** Decode an inline file's `content` to UTF-8 text (e.g. for the percher.toml parse). */
|
|
48
|
+
function fileText(f) {
|
|
49
|
+
return f.encoding === "base64" ? Buffer.from(f.content, "base64").toString("utf8") : f.content;
|
|
50
|
+
}
|
|
51
|
+
/** Total decoded `content` bytes across all inline files. */
|
|
52
|
+
function totalContentBytes(files) {
|
|
53
|
+
let total = 0;
|
|
54
|
+
for (const f of files)
|
|
55
|
+
total += fileBytes(f).length;
|
|
56
|
+
return total;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Hosted "publish from inline source" — the filesystem-free counterpart
|
|
60
|
+
* to {@link publish}. An assistant passes the source files it just
|
|
61
|
+
* generated (including a `percher.toml`) as a tool argument; this builds
|
|
62
|
+
* a tarball entirely in memory and ships it through the curated
|
|
63
|
+
* `POST /apps/publish` endpoint (the only publish surface an OAuth token
|
|
64
|
+
* may reach). It NEVER reads `ctx.cwd`.
|
|
65
|
+
*
|
|
66
|
+
* Returns the same {@link PublishResult} shape + recovery contract as
|
|
67
|
+
* `publish` so an agent's `wait_for_deploy` chain works identically.
|
|
68
|
+
*/
|
|
69
|
+
export async function publishInline(ctx, input) {
|
|
70
|
+
try {
|
|
71
|
+
return await publishInlineInner(ctx, input);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
// Business-rule 403s / gate codes (plan limits, rate limits,
|
|
75
|
+
// quota) classify into a structured failure with the right title +
|
|
76
|
+
// suggestion. Anything else becomes a generic structured failure so
|
|
77
|
+
// an agent always gets JSON, never a raw stack.
|
|
78
|
+
const classified = classifyPublishApiError(err, {
|
|
79
|
+
configPath: TOML_FILENAME,
|
|
80
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
81
|
+
});
|
|
82
|
+
if (classified)
|
|
83
|
+
return classified;
|
|
84
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
85
|
+
const hint = err instanceof PercherApiError ? `API returned ${err.status}: ${err.message}` : undefined;
|
|
86
|
+
return failure({
|
|
87
|
+
title: "Unexpected error",
|
|
88
|
+
explanation: hint ?? message,
|
|
89
|
+
suggestion: "This may be a network issue or a Percher bug. If it persists, run percher_doctor for diagnostics.",
|
|
90
|
+
recovery: recoveryAsk({
|
|
91
|
+
prompt: `Unexpected inline-publish failure: ${hint ?? message}. Surface this to the user or run percher_doctor.`,
|
|
92
|
+
reasonCode: "unknown",
|
|
93
|
+
}),
|
|
94
|
+
summary: `Unexpected error: ${hint ?? message}`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function publishInlineInner(ctx, input) {
|
|
99
|
+
const t0 = Date.now();
|
|
100
|
+
// ── 0. Size guard (defense in depth; the tool + API also enforce) ──
|
|
101
|
+
const contentBytes = totalContentBytes(input.files);
|
|
102
|
+
if (contentBytes > MAX_INLINE_PUBLISH_BYTES) {
|
|
103
|
+
return failure({
|
|
104
|
+
title: "Inline source too large",
|
|
105
|
+
explanation: `The inline files total ${(contentBytes / 1024 / 1024).toFixed(1)} MB, which exceeds the ${MAX_INLINE_PUBLISH_BYTES / 1024 / 1024} MB inline-publish limit.`,
|
|
106
|
+
suggestion: "Inline publishing is for small apps generated in-session. For a larger app, connect a GitHub/Forgejo repo and deploy with percher_deploy.",
|
|
107
|
+
recovery: recoveryAsk({
|
|
108
|
+
prompt: `Inline source is ${(contentBytes / 1024 / 1024).toFixed(1)} MB (limit ${MAX_INLINE_PUBLISH_BYTES / 1024 / 1024} MB). Use the connected-repo deploy path (percher_deploy) for a large app.`,
|
|
109
|
+
reasonCode: "unknown",
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// ── 1. Config — read percher.toml out of the inline files, or, when
|
|
114
|
+
// it's omitted, auto-detect the runtime from the files and
|
|
115
|
+
// synthesize one (injected below so the bundle is self-describing
|
|
116
|
+
// exactly like a user-provided one). ──────────────────────────
|
|
117
|
+
ctx.status("[1/3] Reading inline percher.toml...");
|
|
118
|
+
// The file list shipped in the tarball: input.files, plus a synthesized
|
|
119
|
+
// percher.toml when the caller omitted one.
|
|
120
|
+
let files = input.files;
|
|
121
|
+
let config;
|
|
122
|
+
const tomlFile = input.files.find((f) => normalizeForMatch(f.path) === TOML_FILENAME);
|
|
123
|
+
if (tomlFile) {
|
|
124
|
+
try {
|
|
125
|
+
config = parse(fileText(tomlFile));
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (err instanceof PercherTomlError) {
|
|
129
|
+
const problems = tomlErrorToRecoveryProblems(err);
|
|
130
|
+
const isParse = err.code === "PARSE_ERROR";
|
|
131
|
+
return failure({
|
|
132
|
+
title: isParse
|
|
133
|
+
? "percher.toml has invalid TOML syntax"
|
|
134
|
+
: "percher.toml failed schema validation",
|
|
135
|
+
explanation: err.message,
|
|
136
|
+
suggestion: isParse
|
|
137
|
+
? "Fix the syntax error and retry."
|
|
138
|
+
: "Fix the schema issues (check the percher.toml spec) and retry.",
|
|
139
|
+
recovery: recoveryFixConfig({ problems, reasonCode: "config_invalid" }),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
throw err;
|
|
143
|
+
}
|
|
144
|
+
// `name` arg overrides the percher.toml app name when supplied. Trim to
|
|
145
|
+
// match the no-toml branch (a whitespace-only override is ignored).
|
|
146
|
+
const overrideName = input.name?.trim();
|
|
147
|
+
if (overrideName) {
|
|
148
|
+
config.app.name = overrideName;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// No percher.toml — synthesize one from a runtime auto-detect.
|
|
153
|
+
const name = input.name?.trim();
|
|
154
|
+
if (!name) {
|
|
155
|
+
return failure({
|
|
156
|
+
title: "App name required",
|
|
157
|
+
explanation: "No percher.toml was provided, so Percher can't infer the app name. Pass `name`, or include a percher.toml with [app].name.",
|
|
158
|
+
suggestion: "Re-call percher_publish with `name` set (3-40 chars, lowercase a-z 0-9 and hyphens).",
|
|
159
|
+
recovery: recoveryAsk({
|
|
160
|
+
prompt: "What should the app be named? (3-40 chars, lowercase letters, numbers, and hyphens)",
|
|
161
|
+
reasonCode: "config_missing",
|
|
162
|
+
}),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const detected = detectFrameworkFromFiles(
|
|
166
|
+
// Detection reads only text files (package.json, *.py) and checks file
|
|
167
|
+
// existence; pass "" for base64 (binary) entries so a large asset isn't
|
|
168
|
+
// decoded to text — its path still registers for existence checks.
|
|
169
|
+
input.files.map((f) => ({
|
|
170
|
+
path: f.path,
|
|
171
|
+
content: f.encoding === "base64" ? "" : f.content,
|
|
172
|
+
})));
|
|
173
|
+
if (!detected) {
|
|
174
|
+
return failure({
|
|
175
|
+
title: "Could not detect the app runtime",
|
|
176
|
+
explanation: "No percher.toml was provided and Percher couldn't infer the runtime from the files (no package.json, index.html, requirements.txt, or Dockerfile found).",
|
|
177
|
+
suggestion: "Add a percher.toml with [app] name + runtime (node | bun | python | static | docker).",
|
|
178
|
+
recovery: recoveryFixConfig({
|
|
179
|
+
problems: [
|
|
180
|
+
{
|
|
181
|
+
file: TOML_FILENAME,
|
|
182
|
+
message: "Include a percher.toml with at least [app] name and runtime — Percher couldn't auto-detect the runtime from the files.",
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
reasonCode: "config_missing",
|
|
186
|
+
}),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (detected.staticBuild) {
|
|
190
|
+
// Vite / static-Astro / etc. need a build step that the inline path
|
|
191
|
+
// can't run without a Dockerfile (the Dockerfile branch would have
|
|
192
|
+
// matched first if one were present).
|
|
193
|
+
return failure({
|
|
194
|
+
title: "This project needs a build step",
|
|
195
|
+
explanation: `Detected a ${detected.framework ?? "static"} app that must be built before it can be served, which inline publishing can't do without a Dockerfile.`,
|
|
196
|
+
suggestion: 'Add a percher.toml (runtime = "docker") plus a Dockerfile to the files, or connect a GitHub/Forgejo repo and deploy with percher_deploy.',
|
|
197
|
+
recovery: recoveryFixConfig({
|
|
198
|
+
problems: [
|
|
199
|
+
{
|
|
200
|
+
file: TOML_FILENAME,
|
|
201
|
+
message: "A framework that needs a build step (Vite, static Astro, …) must ship a Dockerfile inline, or be deployed from a connected repo.",
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
reasonCode: "config_missing",
|
|
205
|
+
}),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
config = configFromDetection(name, detected);
|
|
209
|
+
files = [...input.files, { path: TOML_FILENAME, content: serialize(config) }];
|
|
210
|
+
ctx.status(`[1/3] No percher.toml — detected runtime "${config.app.runtime}" from files.`);
|
|
211
|
+
}
|
|
212
|
+
// ── 2. Tarball — built entirely in memory from the inline files ────
|
|
213
|
+
ctx.status("[2/3] Packaging inline files...");
|
|
214
|
+
let tarball;
|
|
215
|
+
try {
|
|
216
|
+
tarball = createTarballFromFiles(files.map((f) => ({ path: f.path, data: fileBytes(f) })), config);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
// createTarballFromFiles rejects traversal / absolute / duplicate
|
|
220
|
+
// paths — an untrusted-input problem, not a Percher bug.
|
|
221
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
222
|
+
return failure({
|
|
223
|
+
title: "Invalid file path in inline source",
|
|
224
|
+
explanation: message,
|
|
225
|
+
suggestion: "Use repo-relative forward-slash paths only — no leading /, no .., no drive letters, no duplicates.",
|
|
226
|
+
recovery: recoveryFixConfig({
|
|
227
|
+
problems: [{ file: "files", message }],
|
|
228
|
+
reasonCode: "config_invalid",
|
|
229
|
+
}),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
const packageMs = Date.now() - t0;
|
|
233
|
+
// ── 3. Upload via the curated /apps/publish endpoint ───────────────
|
|
234
|
+
ctx.status("[3/3] Uploading & deploying...");
|
|
235
|
+
const uploadStart = Date.now();
|
|
236
|
+
const tarballBytes = new Uint8Array(await new Response(tarball.stream).arrayBuffer());
|
|
237
|
+
let deployment;
|
|
238
|
+
try {
|
|
239
|
+
deployment = await ctx.client.apps.publishInline({
|
|
240
|
+
name: config.app.name,
|
|
241
|
+
runtime: config.app.runtime,
|
|
242
|
+
framework: config.app.framework,
|
|
243
|
+
tarball: tarballBytes,
|
|
244
|
+
type: input.preview ? "preview" : undefined,
|
|
245
|
+
note: input.message,
|
|
246
|
+
noCache: input.noCache,
|
|
247
|
+
tarballHash: tarball.contentHash,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
if (err instanceof PercherApiError && DEPLOY_GATE_CODES.has(err.code)) {
|
|
252
|
+
const classified = classifyPublishApiError(err, {
|
|
253
|
+
configPath: TOML_FILENAME,
|
|
254
|
+
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes },
|
|
255
|
+
});
|
|
256
|
+
if (classified)
|
|
257
|
+
return classified;
|
|
258
|
+
}
|
|
259
|
+
throw err;
|
|
260
|
+
}
|
|
261
|
+
// The curated endpoint returns a serialized Deployment; the
|
|
262
|
+
// already_in_progress short-circuit comes back through the same
|
|
263
|
+
// type-union guard the upload path uses.
|
|
264
|
+
if (isDeployAlreadyInProgress(deployment)) {
|
|
265
|
+
const active = deployment;
|
|
266
|
+
return {
|
|
267
|
+
status: "already_in_progress",
|
|
268
|
+
fileCount: tarball.fileCount,
|
|
269
|
+
bytes: tarball.bytes,
|
|
270
|
+
recovery: recoveryWait({
|
|
271
|
+
app: config.app.name,
|
|
272
|
+
deployId: active.deployId,
|
|
273
|
+
reasonCode: active.deployStatus === "queued"
|
|
274
|
+
? "deploy_queued"
|
|
275
|
+
: active.deployStatus === "building"
|
|
276
|
+
? "deploy_building"
|
|
277
|
+
: "deploy_deploying",
|
|
278
|
+
}),
|
|
279
|
+
summary: `${config.app.name} already has a deploy in progress (${active.deployId}) — wait for it instead of queueing a duplicate.`,
|
|
280
|
+
configPath: TOML_FILENAME,
|
|
281
|
+
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes },
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const uploadMs = Date.now() - uploadStart;
|
|
285
|
+
// The app object isn't returned by the publish endpoint; synthesize a
|
|
286
|
+
// minimal one from what we know (name + runtime + the deploy's url) so
|
|
287
|
+
// finalizeDeploy can shape the result. The deployment row carries the
|
|
288
|
+
// live/preview URL once polled, which is what the summary actually uses.
|
|
289
|
+
const app = {
|
|
290
|
+
id: deployment.appId,
|
|
291
|
+
name: config.app.name,
|
|
292
|
+
runtime: config.app.runtime,
|
|
293
|
+
framework: config.app.framework ?? null,
|
|
294
|
+
url: deployment.url ?? `https://${config.app.name}.percher.run`,
|
|
295
|
+
};
|
|
296
|
+
return finalizeDeploy({
|
|
297
|
+
ctx,
|
|
298
|
+
config,
|
|
299
|
+
input: {
|
|
300
|
+
preview: input.preview,
|
|
301
|
+
message: input.message,
|
|
302
|
+
noCache: input.noCache,
|
|
303
|
+
waitForLive: input.waitForLive,
|
|
304
|
+
},
|
|
305
|
+
app,
|
|
306
|
+
firstDeploy: false,
|
|
307
|
+
tarball: { fileCount: tarball.fileCount, bytes: tarball.bytes },
|
|
308
|
+
deployment,
|
|
309
|
+
t0,
|
|
310
|
+
packageMs,
|
|
311
|
+
uploadMs,
|
|
312
|
+
missingBuildEnvKeys: [],
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
/** Forward-slash + lowercase a path so a `./percher.toml` or `PERCHER.TOML`
|
|
316
|
+
* still matches. Only used to LOCATE the toml; the tarball keeps exact paths. */
|
|
317
|
+
function normalizeForMatch(path) {
|
|
318
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "").toLowerCase();
|
|
319
|
+
}
|
|
320
|
+
/** Shared structured-failure shape for the inline path. `configPath` is the
|
|
321
|
+
* inline toml filename (there's no cwd), and bundle stats are zeroed when the
|
|
322
|
+
* failure preceded packaging. */
|
|
323
|
+
function failure(opts) {
|
|
324
|
+
return {
|
|
325
|
+
status: "failed",
|
|
326
|
+
fileCount: 0,
|
|
327
|
+
bytes: 0,
|
|
328
|
+
error: {
|
|
329
|
+
title: opts.title,
|
|
330
|
+
explanation: opts.explanation,
|
|
331
|
+
suggestion: opts.suggestion,
|
|
332
|
+
},
|
|
333
|
+
recovery: opts.recovery,
|
|
334
|
+
summary: opts.summary ?? `${opts.title} — ${opts.explanation}`,
|
|
335
|
+
configPath: TOML_FILENAME,
|
|
336
|
+
bundle: { fileCount: 0, bytes: 0 },
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=publish-inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-inline.js","sourceRoot":"","sources":["../../src/commands/publish-inline.ts"],"names":[],"mappings":"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"}
|