percher 0.4.1 → 0.4.2
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/bin/percher.js +472 -103
- package/dist/package.json +1 -1
- package/dist/src/cli-utils.d.ts +2 -0
- package/dist/src/cli-utils.d.ts.map +1 -1
- package/dist/src/cli-utils.js +16 -0
- package/dist/src/cli-utils.js.map +1 -1
- package/dist/src/commands/apps.d.ts.map +1 -1
- package/dist/src/commands/apps.js +7 -1
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/export.d.ts +4 -0
- package/dist/src/commands/export.d.ts.map +1 -0
- package/dist/src/commands/export.js +18 -0
- package/dist/src/commands/export.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/output.d.ts.map +1 -1
- package/dist/src/output.js +18 -1
- package/dist/src/output.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/percher.js
CHANGED
|
@@ -8824,7 +8824,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8824
8824
|
}
|
|
8825
8825
|
path = url2.path;
|
|
8826
8826
|
}
|
|
8827
|
-
var
|
|
8827
|
+
var isAbsolute3 = exports.isAbsolute(path);
|
|
8828
8828
|
var parts = path.split(/\/+/);
|
|
8829
8829
|
for (var part, up = 0, i = parts.length - 1;i >= 0; i--) {
|
|
8830
8830
|
part = parts[i];
|
|
@@ -8844,7 +8844,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8844
8844
|
}
|
|
8845
8845
|
path = parts.join("/");
|
|
8846
8846
|
if (path === "") {
|
|
8847
|
-
path =
|
|
8847
|
+
path = isAbsolute3 ? "/" : ".";
|
|
8848
8848
|
}
|
|
8849
8849
|
if (url2) {
|
|
8850
8850
|
url2.path = path;
|
|
@@ -101395,7 +101395,7 @@ function finalize(ctx, schema) {
|
|
|
101395
101395
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
101396
101396
|
} else if (ctx.target === "draft-04") {
|
|
101397
101397
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
101398
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
101398
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
101399
101399
|
if (ctx.external?.uri) {
|
|
101400
101400
|
const id = ctx.external.registry.get(schema)?.id;
|
|
101401
101401
|
if (!id)
|
|
@@ -101643,7 +101643,7 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
101643
101643
|
if (val === undefined) {
|
|
101644
101644
|
if (ctx.unrepresentable === "throw") {
|
|
101645
101645
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
101646
|
-
}
|
|
101646
|
+
}
|
|
101647
101647
|
} else if (typeof val === "bigint") {
|
|
101648
101648
|
if (ctx.unrepresentable === "throw") {
|
|
101649
101649
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -104202,7 +104202,8 @@ var devSchema = exports_external.object({
|
|
|
104202
104202
|
var requiredEnvSchema = exports_external.record(exports_external.string(), exports_external.enum(["secret", "url", "string"]));
|
|
104203
104203
|
var cronSchema = exports_external.object({
|
|
104204
104204
|
schedule: exports_external.string().min(1),
|
|
104205
|
-
command: exports_external.string().min(1)
|
|
104205
|
+
command: exports_external.string().min(1),
|
|
104206
|
+
description: exports_external.string().max(200).optional()
|
|
104206
104207
|
}).strict();
|
|
104207
104208
|
var addonsSchema = exports_external.object({
|
|
104208
104209
|
pocketbase: exports_external.object({ enabled: exports_external.boolean().optional() }).strict().optional(),
|
|
@@ -105221,6 +105222,27 @@ function isRestoreJobStatus(v) {
|
|
|
105221
105222
|
return typeof v === "string" && RESTORE_JOB_STATUSES_FOR_ERROR.includes(v);
|
|
105222
105223
|
}
|
|
105223
105224
|
|
|
105225
|
+
class SunsetError extends PercherApiError {
|
|
105226
|
+
gateCode;
|
|
105227
|
+
sunsetDate;
|
|
105228
|
+
finalDeletionDate;
|
|
105229
|
+
dashboardUrl;
|
|
105230
|
+
constructor(message, options) {
|
|
105231
|
+
super(message, options);
|
|
105232
|
+
this.name = "SunsetError";
|
|
105233
|
+
this.gateCode = options.gateCode;
|
|
105234
|
+
this.sunsetDate = options.sunsetDate;
|
|
105235
|
+
this.finalDeletionDate = options.finalDeletionDate;
|
|
105236
|
+
this.dashboardUrl = options.dashboardUrl;
|
|
105237
|
+
}
|
|
105238
|
+
}
|
|
105239
|
+
function isSunsetGateBody(body) {
|
|
105240
|
+
if (typeof body !== "object" || body === null)
|
|
105241
|
+
return false;
|
|
105242
|
+
const b = body;
|
|
105243
|
+
return (b.error === "platform_read_only" || b.error === "platform_delete_gated") && typeof b.sunsetDate === "string" && typeof b.finalDeletionDate === "string" && typeof b.dashboardUrl === "string";
|
|
105244
|
+
}
|
|
105245
|
+
|
|
105224
105246
|
// ../client/dist/http.js
|
|
105225
105247
|
class Http {
|
|
105226
105248
|
apiUrl;
|
|
@@ -105342,10 +105364,23 @@ class Http {
|
|
|
105342
105364
|
return headers;
|
|
105343
105365
|
}
|
|
105344
105366
|
async parseError(res) {
|
|
105345
|
-
let
|
|
105367
|
+
let raw;
|
|
105346
105368
|
try {
|
|
105347
|
-
|
|
105369
|
+
raw = await res.json();
|
|
105348
105370
|
} catch {}
|
|
105371
|
+
if (res.status === 503 && isSunsetGateBody(raw)) {
|
|
105372
|
+
const requestIdHdr = res.headers.get("x-request-id") ?? undefined;
|
|
105373
|
+
return new SunsetError(raw.message, {
|
|
105374
|
+
status: res.status,
|
|
105375
|
+
code: raw.error,
|
|
105376
|
+
requestId: requestIdHdr,
|
|
105377
|
+
gateCode: raw.error,
|
|
105378
|
+
sunsetDate: raw.sunsetDate,
|
|
105379
|
+
finalDeletionDate: raw.finalDeletionDate,
|
|
105380
|
+
dashboardUrl: raw.dashboardUrl
|
|
105381
|
+
});
|
|
105382
|
+
}
|
|
105383
|
+
const body = typeof raw === "object" && raw !== null ? raw : {};
|
|
105349
105384
|
const code = body.error?.code ?? (res.status >= 500 ? "INTERNAL_ERROR" : "VALIDATION_ERROR");
|
|
105350
105385
|
const message = body.error?.message ?? res.statusText ?? "request failed";
|
|
105351
105386
|
const extra = {};
|
|
@@ -105385,6 +105420,12 @@ class AccountResource {
|
|
|
105385
105420
|
getDiagnostics() {
|
|
105386
105421
|
return this.http.get("/account/diagnostics");
|
|
105387
105422
|
}
|
|
105423
|
+
listTokens() {
|
|
105424
|
+
return this.http.get("/account/tokens");
|
|
105425
|
+
}
|
|
105426
|
+
revokeToken(id) {
|
|
105427
|
+
return this.http.delete(`/account/tokens/${encodeURIComponent(id)}`);
|
|
105428
|
+
}
|
|
105388
105429
|
exportData() {
|
|
105389
105430
|
return this.http.get("/account/export");
|
|
105390
105431
|
}
|
|
@@ -105426,6 +105467,9 @@ class AppsResource {
|
|
|
105426
105467
|
list() {
|
|
105427
105468
|
return this.http.get("/apps");
|
|
105428
105469
|
}
|
|
105470
|
+
listLight() {
|
|
105471
|
+
return this.http.get("/apps?light=1");
|
|
105472
|
+
}
|
|
105429
105473
|
get(id) {
|
|
105430
105474
|
return this.http.get(`/apps/${encodeURIComponent(id)}`);
|
|
105431
105475
|
}
|
|
@@ -105461,6 +105505,37 @@ class AppsResource {
|
|
|
105461
105505
|
crashAnalysisEnabled: enabled
|
|
105462
105506
|
});
|
|
105463
105507
|
}
|
|
105508
|
+
setGalleryOptIn(appRef, enabled) {
|
|
105509
|
+
return this.http.put(`/apps/${encodeURIComponent(appRef)}/gallery-opt-in`, {
|
|
105510
|
+
enabled
|
|
105511
|
+
});
|
|
105512
|
+
}
|
|
105513
|
+
setDescription(appRef, description) {
|
|
105514
|
+
return this.http.patch(`/apps/${encodeURIComponent(appRef)}/description`, {
|
|
105515
|
+
description
|
|
105516
|
+
});
|
|
105517
|
+
}
|
|
105518
|
+
setIconColour(appRef, colour) {
|
|
105519
|
+
return this.http.patch(`/apps/${encodeURIComponent(appRef)}/icon`, {
|
|
105520
|
+
colour
|
|
105521
|
+
});
|
|
105522
|
+
}
|
|
105523
|
+
uploadIconImage(appRef, bytes, mime) {
|
|
105524
|
+
const ab = new ArrayBuffer(bytes.byteLength);
|
|
105525
|
+
new Uint8Array(ab).set(bytes);
|
|
105526
|
+
return this.http.postBinary(`/apps/${encodeURIComponent(appRef)}/icon/image`, new Blob([ab]), { "Content-Type": mime });
|
|
105527
|
+
}
|
|
105528
|
+
deleteIconImage(appRef) {
|
|
105529
|
+
return this.http.deleteJson(`/apps/${encodeURIComponent(appRef)}/icon/image`);
|
|
105530
|
+
}
|
|
105531
|
+
uploadPreviewImage(appRef, bytes, mime) {
|
|
105532
|
+
const ab = new ArrayBuffer(bytes.byteLength);
|
|
105533
|
+
new Uint8Array(ab).set(bytes);
|
|
105534
|
+
return this.http.postBinary(`/apps/${encodeURIComponent(appRef)}/preview/image`, new Blob([ab]), { "Content-Type": mime });
|
|
105535
|
+
}
|
|
105536
|
+
deletePreviewImage(appRef) {
|
|
105537
|
+
return this.http.deleteJson(`/apps/${encodeURIComponent(appRef)}/preview/image`);
|
|
105538
|
+
}
|
|
105464
105539
|
async downloadSource(appRef, deployId) {
|
|
105465
105540
|
return this.http.getBinary(`/apps/${encodeURIComponent(appRef)}/deploys/${encodeURIComponent(deployId)}/source`);
|
|
105466
105541
|
}
|
|
@@ -105545,12 +105620,18 @@ class AppsResource {
|
|
|
105545
105620
|
listJobs(appRef, limit = 20) {
|
|
105546
105621
|
return this.http.get(`/apps/${encodeURIComponent(appRef)}/jobs?limit=${limit}`);
|
|
105547
105622
|
}
|
|
105623
|
+
listCrons(appRef) {
|
|
105624
|
+
return this.http.get(`/apps/${encodeURIComponent(appRef)}/crons`);
|
|
105625
|
+
}
|
|
105548
105626
|
getDiagnostics(appRef) {
|
|
105549
105627
|
return this.http.get(`/apps/${encodeURIComponent(appRef)}/diagnostics`);
|
|
105550
105628
|
}
|
|
105551
105629
|
getTopology(appRef) {
|
|
105552
105630
|
return this.http.get(`/apps/${encodeURIComponent(appRef)}/topology`);
|
|
105553
105631
|
}
|
|
105632
|
+
getPocketBaseVolume(appRef) {
|
|
105633
|
+
return this.http.get(`/apps/${encodeURIComponent(appRef)}/pocketbase/volume`);
|
|
105634
|
+
}
|
|
105554
105635
|
getResources(appRef, opts = {}) {
|
|
105555
105636
|
const params = new URLSearchParams;
|
|
105556
105637
|
if (opts.window)
|
|
@@ -105712,6 +105793,40 @@ class EnvResource {
|
|
|
105712
105793
|
}
|
|
105713
105794
|
}
|
|
105714
105795
|
|
|
105796
|
+
// ../client/dist/resources/env-scan.js
|
|
105797
|
+
class EnvScanResource {
|
|
105798
|
+
http;
|
|
105799
|
+
constructor(http) {
|
|
105800
|
+
this.http = http;
|
|
105801
|
+
}
|
|
105802
|
+
scan(appId) {
|
|
105803
|
+
return this.http.post(`/apps/${encodeURIComponent(appId)}/env-scan`);
|
|
105804
|
+
}
|
|
105805
|
+
}
|
|
105806
|
+
|
|
105807
|
+
// ../client/dist/resources/export.js
|
|
105808
|
+
class ExportResource {
|
|
105809
|
+
http;
|
|
105810
|
+
constructor(http) {
|
|
105811
|
+
this.http = http;
|
|
105812
|
+
}
|
|
105813
|
+
mint(appRef, options) {
|
|
105814
|
+
return this.http.post(`/apps/${encodeURIComponent(appRef)}/export/mint`, {
|
|
105815
|
+
deliveryKind: options?.deliveryKind
|
|
105816
|
+
});
|
|
105817
|
+
}
|
|
105818
|
+
revoke(appRef, tokenId) {
|
|
105819
|
+
return this.http.post(`/apps/${encodeURIComponent(appRef)}/export/tokens/${encodeURIComponent(tokenId)}/revoke`);
|
|
105820
|
+
}
|
|
105821
|
+
history(appRef) {
|
|
105822
|
+
return this.http.get(`/apps/${encodeURIComponent(appRef)}/export/history`);
|
|
105823
|
+
}
|
|
105824
|
+
async download(downloadUrl) {
|
|
105825
|
+
const path = downloadUrl.startsWith("http") ? new URL(downloadUrl).pathname + new URL(downloadUrl).search : downloadUrl;
|
|
105826
|
+
return this.http.stream(path);
|
|
105827
|
+
}
|
|
105828
|
+
}
|
|
105829
|
+
|
|
105715
105830
|
// ../client/dist/sse.js
|
|
105716
105831
|
async function* parseSseStream(stream, signal) {
|
|
105717
105832
|
const reader = stream.getReader();
|
|
@@ -105859,6 +105974,43 @@ class PlatformResource {
|
|
|
105859
105974
|
}
|
|
105860
105975
|
}
|
|
105861
105976
|
|
|
105977
|
+
// ../client/dist/resources/search.js
|
|
105978
|
+
class SearchResource {
|
|
105979
|
+
http;
|
|
105980
|
+
constructor(http) {
|
|
105981
|
+
this.http = http;
|
|
105982
|
+
}
|
|
105983
|
+
query(q) {
|
|
105984
|
+
return this.http.get(`/search?q=${encodeURIComponent(q)}`);
|
|
105985
|
+
}
|
|
105986
|
+
}
|
|
105987
|
+
|
|
105988
|
+
// ../client/dist/resources/security.js
|
|
105989
|
+
class SecurityResource {
|
|
105990
|
+
http;
|
|
105991
|
+
constructor(http) {
|
|
105992
|
+
this.http = http;
|
|
105993
|
+
}
|
|
105994
|
+
forApp(appRef) {
|
|
105995
|
+
return this.http.get(`/apps/${encodeURIComponent(appRef)}/security`);
|
|
105996
|
+
}
|
|
105997
|
+
forAppAsAdmin(appRef) {
|
|
105998
|
+
return this.http.get(`/admin/security/apps/${encodeURIComponent(appRef)}`);
|
|
105999
|
+
}
|
|
106000
|
+
resendNotificationAsAdmin(appRef) {
|
|
106001
|
+
return this.http.post(`/admin/security/apps/${encodeURIComponent(appRef)}/notify`, {});
|
|
106002
|
+
}
|
|
106003
|
+
overview() {
|
|
106004
|
+
return this.http.get("/admin/security/overview");
|
|
106005
|
+
}
|
|
106006
|
+
rescanAllAsAdmin() {
|
|
106007
|
+
return this.http.post("/admin/security/rescan", {});
|
|
106008
|
+
}
|
|
106009
|
+
rescanAppAsAdmin(appRef) {
|
|
106010
|
+
return this.http.post(`/admin/security/apps/${encodeURIComponent(appRef)}/rescan`, {});
|
|
106011
|
+
}
|
|
106012
|
+
}
|
|
106013
|
+
|
|
105862
106014
|
// ../client/dist/resources/sharing.js
|
|
105863
106015
|
class SharingResource {
|
|
105864
106016
|
http;
|
|
@@ -105929,12 +106081,16 @@ class PercherClient {
|
|
|
105929
106081
|
apps;
|
|
105930
106082
|
data;
|
|
105931
106083
|
env;
|
|
106084
|
+
envScan;
|
|
106085
|
+
export;
|
|
105932
106086
|
logs;
|
|
105933
106087
|
auth;
|
|
105934
106088
|
billing;
|
|
105935
106089
|
account;
|
|
105936
106090
|
alerts;
|
|
105937
106091
|
platform;
|
|
106092
|
+
security;
|
|
106093
|
+
search;
|
|
105938
106094
|
sharing;
|
|
105939
106095
|
invites;
|
|
105940
106096
|
transfers;
|
|
@@ -105953,12 +106109,16 @@ class PercherClient {
|
|
|
105953
106109
|
this.apps = new AppsResource(http);
|
|
105954
106110
|
this.data = new DataResource(http);
|
|
105955
106111
|
this.env = new EnvResource(http);
|
|
106112
|
+
this.envScan = new EnvScanResource(http);
|
|
106113
|
+
this.export = new ExportResource(http);
|
|
105956
106114
|
this.logs = new LogsResource(http);
|
|
105957
106115
|
this.auth = new AuthResource(http);
|
|
105958
106116
|
this.billing = new BillingResource(http);
|
|
105959
106117
|
this.account = new AccountResource(http);
|
|
105960
106118
|
this.alerts = new AlertsResource(http);
|
|
105961
106119
|
this.platform = new PlatformResource(http);
|
|
106120
|
+
this.security = new SecurityResource(http);
|
|
106121
|
+
this.search = new SearchResource(http);
|
|
105962
106122
|
this.sharing = new SharingResource(http);
|
|
105963
106123
|
this.invites = new InvitesResource(http);
|
|
105964
106124
|
this.transfers = new TransfersResource(http);
|
|
@@ -106418,6 +106578,19 @@ var patterns = [
|
|
|
106418
106578
|
missingEnvVars: []
|
|
106419
106579
|
}
|
|
106420
106580
|
},
|
|
106581
|
+
{
|
|
106582
|
+
pattern: /Bad Gateway|HTTP 502|\b502\b/i,
|
|
106583
|
+
result: {
|
|
106584
|
+
title: "Gateway error (transient)",
|
|
106585
|
+
explanation: "A gateway in front of your app returned 502 Bad Gateway while the platform was routing the deploy. This is a transient platform-side hiccup, not your app code.",
|
|
106586
|
+
suggestion: "Wait 30 seconds and run percher publish again. A single retry almost always lands cleanly. If 502s persist across several spaced-out retries, check status.percher.app — that's a platform incident, not your app.",
|
|
106587
|
+
errorClass: "infra_unavailable",
|
|
106588
|
+
phase: "infra",
|
|
106589
|
+
cause: "bad_gateway",
|
|
106590
|
+
relevantFiles: [],
|
|
106591
|
+
missingEnvVars: []
|
|
106592
|
+
}
|
|
106593
|
+
},
|
|
106421
106594
|
{
|
|
106422
106595
|
pattern: /start command could not be found|no start command/i,
|
|
106423
106596
|
result: {
|
|
@@ -106536,7 +106709,20 @@ var patterns = [
|
|
|
106536
106709
|
}
|
|
106537
106710
|
},
|
|
106538
106711
|
{
|
|
106539
|
-
pattern: /
|
|
106712
|
+
pattern: /committed_budget|\bbox admission|platform (?:is )?at capacity/i,
|
|
106713
|
+
result: {
|
|
106714
|
+
title: "Platform at capacity",
|
|
106715
|
+
explanation: "The platform couldn't fit this deploy right now — the box is full, so the box-admission gate refused to start the container. This is a platform-side limit, not a problem with your app code or configuration.",
|
|
106716
|
+
suggestion: "Wait a few minutes and run percher publish again — capacity frees up as other deploys finish. This failure does not count against your app, and a retry usually lands once there's room. If it persists, contact the operator.",
|
|
106717
|
+
errorClass: "platform_at_capacity",
|
|
106718
|
+
phase: "infra",
|
|
106719
|
+
cause: "box_admission_rejected",
|
|
106720
|
+
relevantFiles: [],
|
|
106721
|
+
missingEnvVars: []
|
|
106722
|
+
}
|
|
106723
|
+
},
|
|
106724
|
+
{
|
|
106725
|
+
pattern: /pocketbase[^\n]{0,40}(?:error|fail|crash|panic|exit|unhealthy|could ?not|cannot|connection refused|timed out|not (?:start|ready|reachable))|(?:failed to (?:start|connect|reach)|error (?:starting|connecting to)|unable to (?:start|reach|connect to))[^\n]{0,40}pocketbase/i,
|
|
106540
106726
|
result: {
|
|
106541
106727
|
title: "PocketBase error",
|
|
106542
106728
|
explanation: "PocketBase could not start or connect properly.",
|
|
@@ -106819,6 +107005,12 @@ function recoveryFromErrorClass(errorClass, failure = {}) {
|
|
|
106819
107005
|
args: failure.publishInput ?? {},
|
|
106820
107006
|
reasonCode: "infra_unavailable"
|
|
106821
107007
|
});
|
|
107008
|
+
case "platform_at_capacity":
|
|
107009
|
+
return recoveryRetry({
|
|
107010
|
+
suggestedTool: "percher_publish",
|
|
107011
|
+
args: failure.publishInput ?? {},
|
|
107012
|
+
reasonCode: "infra_transient"
|
|
107013
|
+
});
|
|
106822
107014
|
case "config_invalid":
|
|
106823
107015
|
return recoveryFixConfig({
|
|
106824
107016
|
problems: [
|
|
@@ -106987,7 +107179,7 @@ async function buildFailureError(ctx, app, deployment) {
|
|
|
106987
107179
|
buildLogFetchFailed = true;
|
|
106988
107180
|
}
|
|
106989
107181
|
const errorMessage = deployment.errorMessage ?? "";
|
|
106990
|
-
const classified = classifyByErrorCode(deployment.errorCode, errorMessage) ?? classifyError("Deployment failed", fullLog)
|
|
107182
|
+
const classified = classifyByErrorCode(deployment.errorCode, errorMessage) ?? classifyError(errorMessage || "Deployment failed", fullLog);
|
|
106991
107183
|
const rawErrorMessage = errorMessage && !buildLogTail && !classified?.explanation.includes(errorMessage) ? errorMessage : undefined;
|
|
106992
107184
|
const problems = deployment.problems && deployment.problems.length > 0 ? deployment.problems : undefined;
|
|
106993
107185
|
if (classified) {
|
|
@@ -107858,6 +108050,82 @@ async function envList(ctx, input = {}) {
|
|
|
107858
108050
|
masked[k] = mask(v);
|
|
107859
108051
|
return masked;
|
|
107860
108052
|
}
|
|
108053
|
+
// ../core/dist/commands/export.js
|
|
108054
|
+
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
108055
|
+
var exportInputSchema = exports_external.object({
|
|
108056
|
+
app: exports_external.string().optional(),
|
|
108057
|
+
out: exports_external.string().optional(),
|
|
108058
|
+
deliveryKind: exports_external.enum(["cli", "mcp"]).default("cli")
|
|
108059
|
+
});
|
|
108060
|
+
function resolveAppName3(ctx, provided) {
|
|
108061
|
+
const name = provided ?? readPercherTomlAppName(ctx.cwd);
|
|
108062
|
+
if (!name) {
|
|
108063
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108064
|
+
code: "export.no-app",
|
|
108065
|
+
hint: "Pass --app <name> or run from a directory with percher.toml."
|
|
108066
|
+
});
|
|
108067
|
+
}
|
|
108068
|
+
return name;
|
|
108069
|
+
}
|
|
108070
|
+
async function streamToFile(outPath, source) {
|
|
108071
|
+
const file2 = Bun.file(outPath);
|
|
108072
|
+
const writer = file2.writer();
|
|
108073
|
+
let bytes = 0;
|
|
108074
|
+
const reader = source.getReader();
|
|
108075
|
+
try {
|
|
108076
|
+
while (true) {
|
|
108077
|
+
const { done, value } = await reader.read();
|
|
108078
|
+
if (done)
|
|
108079
|
+
break;
|
|
108080
|
+
if (value && value.length > 0) {
|
|
108081
|
+
writer.write(value);
|
|
108082
|
+
bytes += value.length;
|
|
108083
|
+
}
|
|
108084
|
+
}
|
|
108085
|
+
await writer.end();
|
|
108086
|
+
} catch (err) {
|
|
108087
|
+
try {
|
|
108088
|
+
await writer.end();
|
|
108089
|
+
} catch {}
|
|
108090
|
+
try {
|
|
108091
|
+
await Bun.write(outPath, "");
|
|
108092
|
+
await Bun.file(outPath).delete?.();
|
|
108093
|
+
} catch {}
|
|
108094
|
+
throw err;
|
|
108095
|
+
}
|
|
108096
|
+
return { bytes };
|
|
108097
|
+
}
|
|
108098
|
+
function resolveOutPath(ctxCwd, filename) {
|
|
108099
|
+
if (isAbsolute(filename))
|
|
108100
|
+
return filename;
|
|
108101
|
+
return resolvePath(ctxCwd, filename);
|
|
108102
|
+
}
|
|
108103
|
+
async function exportApp(ctx, input) {
|
|
108104
|
+
const name = resolveAppName3(ctx, input.app);
|
|
108105
|
+
const mint = await ctx.client.export.mint(name, { deliveryKind: input.deliveryKind });
|
|
108106
|
+
const dl = await ctx.client.export.download(mint.downloadUrl);
|
|
108107
|
+
if (!dl.body) {
|
|
108108
|
+
throw new PercherCoreError("Export download returned an empty body", {
|
|
108109
|
+
code: "export.empty-body",
|
|
108110
|
+
hint: "Try again — the link is single-use, so a new mint is required."
|
|
108111
|
+
});
|
|
108112
|
+
}
|
|
108113
|
+
const filenameFromHeader = (() => {
|
|
108114
|
+
const cd = dl.headers.get("Content-Disposition") ?? "";
|
|
108115
|
+
const m = cd.match(/filename="?([^";]+)"?/);
|
|
108116
|
+
return m?.[1];
|
|
108117
|
+
})();
|
|
108118
|
+
const filename = input.out ?? filenameFromHeader ?? `${name}-export.tar.gz`;
|
|
108119
|
+
const outPath = resolveOutPath(ctx.cwd, filename);
|
|
108120
|
+
const { bytes } = await streamToFile(outPath, dl.body);
|
|
108121
|
+
return {
|
|
108122
|
+
appName: name,
|
|
108123
|
+
outPath,
|
|
108124
|
+
bytes,
|
|
108125
|
+
expiresAt: mint.expiresAt,
|
|
108126
|
+
includedSecrets: false
|
|
108127
|
+
};
|
|
108128
|
+
}
|
|
107861
108129
|
// ../core/dist/commands/forgejo.js
|
|
107862
108130
|
var FORGEJO_URL_RE = /^https:\/\/[\w.-]+\/[\w.-]+\/[\w.-]+(\.git)?$/;
|
|
107863
108131
|
var forgejoConnectInputSchema = exports_external.object({
|
|
@@ -108728,6 +108996,26 @@ async function login(ctx, input = {}) {
|
|
|
108728
108996
|
}
|
|
108729
108997
|
// ../shared/dist/logs.js
|
|
108730
108998
|
var MAX_LOG_SEARCH_LENGTH = 256;
|
|
108999
|
+
// ../shared/dist/platform-env.js
|
|
109000
|
+
var PERCHER_INJECTED_ENV_KEYS = new Set([
|
|
109001
|
+
"NODE_ENV",
|
|
109002
|
+
"PORT",
|
|
109003
|
+
"DATABASE_URL",
|
|
109004
|
+
"POCKETBASE_URL",
|
|
109005
|
+
"POCKETBASE_ADMIN_EMAIL",
|
|
109006
|
+
"POCKETBASE_ADMIN_PASSWORD",
|
|
109007
|
+
"PERCHER_APP_NAME",
|
|
109008
|
+
"PERCHER_APP_URL",
|
|
109009
|
+
"HTTP_PROXY",
|
|
109010
|
+
"HTTPS_PROXY",
|
|
109011
|
+
"NO_PROXY",
|
|
109012
|
+
"NODE_USE_ENV_PROXY"
|
|
109013
|
+
]);
|
|
109014
|
+
var PROXY_LOWERCASE_ALIASES = new Set([
|
|
109015
|
+
"http_proxy",
|
|
109016
|
+
"https_proxy",
|
|
109017
|
+
"no_proxy"
|
|
109018
|
+
]);
|
|
108731
109019
|
// ../shared/dist/runtime.js
|
|
108732
109020
|
var DEFAULT_NODE_VERSION_MAJOR = "24";
|
|
108733
109021
|
var DEFAULT_NODE_VERSION_LABEL = `${DEFAULT_NODE_VERSION_MAJOR} LTS`;
|
|
@@ -109641,7 +109929,7 @@ function collectWarnings2(collections, rlsPolicies, unsupported) {
|
|
|
109641
109929
|
}
|
|
109642
109930
|
// ../core/dist/commands/migrate-supabase-schema.js
|
|
109643
109931
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
109644
|
-
import { isAbsolute, join as join17, relative as relative3, resolve as resolve6 } from "node:path";
|
|
109932
|
+
import { isAbsolute as isAbsolute2, join as join17, relative as relative3, resolve as resolve6 } from "node:path";
|
|
109645
109933
|
|
|
109646
109934
|
// ../core/dist/commands/migrate-supabase-scripts.js
|
|
109647
109935
|
function generateDataImportScripts(preview) {
|
|
@@ -110154,7 +110442,7 @@ async function migrateSupabaseSchema(ctx, input) {
|
|
|
110154
110442
|
}
|
|
110155
110443
|
function resolveOutputDir(cwd, requested) {
|
|
110156
110444
|
const raw = requested ?? "./migration-preview";
|
|
110157
|
-
return
|
|
110445
|
+
return isAbsolute2(raw) ? raw : resolve6(cwd, raw);
|
|
110158
110446
|
}
|
|
110159
110447
|
async function writePreviewFiles(ctx, outputDir, preview) {
|
|
110160
110448
|
await mkdir2(outputDir, { recursive: true });
|
|
@@ -110927,14 +111215,46 @@ function matchSuspended(err) {
|
|
|
110927
111215
|
function matchAppSuspended(err) {
|
|
110928
111216
|
if (err.code !== "APP_SUSPENDED" || err.status !== 403)
|
|
110929
111217
|
return null;
|
|
111218
|
+
const liftAfterRaw = typeof err.extra?.liftAfter === "string" ? err.extra.liftAfter : null;
|
|
111219
|
+
const liftableNow = err.extra?.liftableNow === true;
|
|
111220
|
+
const canLiftViaPublish = err.extra?.canLiftViaPublish === true;
|
|
111221
|
+
const fixInstructions = typeof err.extra?.fixInstructions === "string" && err.extra.fixInstructions.length > 0 ? err.extra.fixInstructions : null;
|
|
111222
|
+
let suggestion;
|
|
111223
|
+
let prompt;
|
|
111224
|
+
let options;
|
|
111225
|
+
if (canLiftViaPublish && liftableNow) {
|
|
111226
|
+
suggestion = fixInstructions ? `Fix the underlying cause (${fixInstructions}) and run \`percher publish\` — a successful deploy will lift the suspension automatically.` : "Fix the underlying cause and run `percher publish` — a successful deploy will lift the suspension automatically.";
|
|
111227
|
+
prompt = fixInstructions ? `${err.message}
|
|
111228
|
+
|
|
111229
|
+
The suspension window has passed. Fix the underlying cause per the admin's instructions (${fixInstructions}), then run \`percher publish\` — a successful deploy will lift the suspension.` : `${err.message}
|
|
111230
|
+
|
|
111231
|
+
The suspension window has passed. Fix the underlying cause, then run \`percher publish\` — a successful deploy will lift the suspension.`;
|
|
111232
|
+
options = ["fix and republish", "open dashboard", "contact support"];
|
|
111233
|
+
} else if (canLiftViaPublish && liftAfterRaw) {
|
|
111234
|
+
suggestion = fixInstructions ? `Wait until ${liftAfterRaw}, then fix the underlying cause (${fixInstructions}) and run \`percher publish\`. A successful deploy after the window passes will lift the suspension.` : `Wait until ${liftAfterRaw}, then run \`percher publish\`. A successful deploy after the window passes will lift the suspension.`;
|
|
111235
|
+
prompt = `${err.message}
|
|
111236
|
+
|
|
111237
|
+
You can try again after ${liftAfterRaw}. Until then, retrying will fail.`;
|
|
111238
|
+
options = ["wait and republish", "open dashboard", "contact support"];
|
|
111239
|
+
} else if (liftAfterRaw) {
|
|
111240
|
+
suggestion = `A Percher admin will review the suspension after ${liftAfterRaw}. Contact support if you need it lifted sooner.`;
|
|
111241
|
+
prompt = `${err.message}
|
|
111242
|
+
|
|
111243
|
+
Admin will review after ${liftAfterRaw}. Contact support at https://percher.app if you need it lifted sooner.`;
|
|
111244
|
+
options = ["wait", "contact support"];
|
|
111245
|
+
} else {
|
|
111246
|
+
suggestion = "Contact support at https://percher.app or check the dashboard for unsuspend options. Re-publishing won't unsuspend the app.";
|
|
111247
|
+
prompt = `${err.message} Open https://percher.app or contact support — re-publish won't help until the app is unsuspended.`;
|
|
111248
|
+
options = ["contact support", "open dashboard"];
|
|
111249
|
+
}
|
|
110930
111250
|
return {
|
|
110931
111251
|
title: "App suspended",
|
|
110932
111252
|
explanation: err.message,
|
|
110933
|
-
suggestion
|
|
111253
|
+
suggestion,
|
|
110934
111254
|
recovery: recoveryAsk({
|
|
110935
|
-
prompt
|
|
110936
|
-
options
|
|
110937
|
-
reasonCode: "
|
|
111255
|
+
prompt,
|
|
111256
|
+
options,
|
|
111257
|
+
reasonCode: "app_suspended"
|
|
110938
111258
|
}),
|
|
110939
111259
|
summary: `App suspended: ${err.message}`
|
|
110940
111260
|
};
|
|
@@ -113059,6 +113379,7 @@ var SOURCE_EXTS2 = new Set([
|
|
|
113059
113379
|
]);
|
|
113060
113380
|
var DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
|
|
113061
113381
|
// ../core/dist/plans.js
|
|
113382
|
+
var PB_INITIAL_FOOTPRINT_MB = 256;
|
|
113062
113383
|
var PLAN_CATALOG = {
|
|
113063
113384
|
free: {
|
|
113064
113385
|
label: "Free",
|
|
@@ -113080,7 +113401,7 @@ var PLAN_CATALOG = {
|
|
|
113080
113401
|
logRetentionDays: 1,
|
|
113081
113402
|
buildLogRetentionDays: 3,
|
|
113082
113403
|
cronJobs: 1,
|
|
113083
|
-
storageMb:
|
|
113404
|
+
storageMb: PB_INITIAL_FOOTPRINT_MB,
|
|
113084
113405
|
instances: 1,
|
|
113085
113406
|
kvStorageMb: 10,
|
|
113086
113407
|
uptimeIntervalSec: 0,
|
|
@@ -113112,7 +113433,7 @@ var PLAN_CATALOG = {
|
|
|
113112
113433
|
logRetentionDays: 7,
|
|
113113
113434
|
buildLogRetentionDays: 14,
|
|
113114
113435
|
cronJobs: 3,
|
|
113115
|
-
storageMb:
|
|
113436
|
+
storageMb: PB_INITIAL_FOOTPRINT_MB,
|
|
113116
113437
|
instances: 1,
|
|
113117
113438
|
kvStorageMb: 50,
|
|
113118
113439
|
uptimeIntervalSec: 300,
|
|
@@ -113144,7 +113465,7 @@ var PLAN_CATALOG = {
|
|
|
113144
113465
|
logRetentionDays: 30,
|
|
113145
113466
|
buildLogRetentionDays: 30,
|
|
113146
113467
|
cronJobs: 10,
|
|
113147
|
-
storageMb:
|
|
113468
|
+
storageMb: PB_INITIAL_FOOTPRINT_MB,
|
|
113148
113469
|
instances: 2,
|
|
113149
113470
|
kvStorageMb: 200,
|
|
113150
113471
|
uptimeIntervalSec: 60,
|
|
@@ -113176,7 +113497,7 @@ var PLAN_CATALOG = {
|
|
|
113176
113497
|
logRetentionDays: 90,
|
|
113177
113498
|
buildLogRetentionDays: 90,
|
|
113178
113499
|
cronJobs: 25,
|
|
113179
|
-
storageMb:
|
|
113500
|
+
storageMb: PB_INITIAL_FOOTPRINT_MB,
|
|
113180
113501
|
instances: 4,
|
|
113181
113502
|
kvStorageMb: 1000,
|
|
113182
113503
|
uptimeIntervalSec: 30,
|
|
@@ -113290,6 +113611,18 @@ function formatStatus(status2) {
|
|
|
113290
113611
|
return import_picocolors.default.red(status2);
|
|
113291
113612
|
return import_picocolors.default.yellow(status2);
|
|
113292
113613
|
}
|
|
113614
|
+
function formatBytes(bytes) {
|
|
113615
|
+
if (!Number.isFinite(bytes) || bytes < 0)
|
|
113616
|
+
return "—";
|
|
113617
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
113618
|
+
let n = bytes;
|
|
113619
|
+
let i = 0;
|
|
113620
|
+
while (n >= 1024 && i < units.length - 1) {
|
|
113621
|
+
n /= 1024;
|
|
113622
|
+
i += 1;
|
|
113623
|
+
}
|
|
113624
|
+
return `${i === 0 ? n : n.toFixed(1)} ${units[i]}`;
|
|
113625
|
+
}
|
|
113293
113626
|
function firstNonFlagAfter(argv, from, valueFlags = new Set) {
|
|
113294
113627
|
let i = from + 1;
|
|
113295
113628
|
while (i < argv.length) {
|
|
@@ -113329,6 +113662,9 @@ async function runDeploysInspect(ctx, input) {
|
|
|
113329
113662
|
await writeLine(ctx, `${import_picocolors.default.bold("Type:")} ${deploy.type}`);
|
|
113330
113663
|
}
|
|
113331
113664
|
await writeLine(ctx, `${import_picocolors.default.bold("Created:")} ${formatDeployTimestamp(deploy.createdAt)}`);
|
|
113665
|
+
if (typeof deploy.imageSizeBytes === "number") {
|
|
113666
|
+
await writeLine(ctx, `${import_picocolors.default.bold("Image:")} ${formatBytes(deploy.imageSizeBytes)}`);
|
|
113667
|
+
}
|
|
113332
113668
|
if (deploy.url) {
|
|
113333
113669
|
await writeLine(ctx, `${import_picocolors.default.bold("URL:")} ${deploy.url}`);
|
|
113334
113670
|
}
|
|
@@ -113789,6 +114125,9 @@ async function handlePublishResult(ctx, result, options = {}) {
|
|
|
113789
114125
|
await writeLine(ctx, import_picocolors4.default.dim(" Build cache: miss (fresh build)"));
|
|
113790
114126
|
}
|
|
113791
114127
|
}
|
|
114128
|
+
if (typeof result.deployment?.imageSizeBytes === "number") {
|
|
114129
|
+
await writeLine(ctx, import_picocolors4.default.dim(` Image size: ${formatBytes(result.deployment.imageSizeBytes)}`));
|
|
114130
|
+
}
|
|
113792
114131
|
if (result.replacedPreview) {
|
|
113793
114132
|
await writeLine(ctx, import_picocolors4.default.dim(" (replaced previous preview — free plan keeps 1 preview slot per app)"));
|
|
113794
114133
|
}
|
|
@@ -113897,6 +114236,9 @@ function registerAppsCommands(cli, ctx) {
|
|
|
113897
114236
|
} else if (status2 === "fresh") {
|
|
113898
114237
|
await writeLine(ctx, import_picocolors4.default.dim(" Build cache: miss (fresh build)"));
|
|
113899
114238
|
}
|
|
114239
|
+
if (typeof result.deployment?.imageSizeBytes === "number") {
|
|
114240
|
+
await writeLine(ctx, import_picocolors4.default.dim(` Image size: ${formatBytes(result.deployment.imageSizeBytes)}`));
|
|
114241
|
+
}
|
|
113900
114242
|
}
|
|
113901
114243
|
});
|
|
113902
114244
|
cli.command("rename <name> [app]", "Rename an app (changes its subdomain)").action(async (name, app) => {
|
|
@@ -114318,10 +114660,24 @@ function registerEnvCommands(cli, ctx) {
|
|
|
114318
114660
|
});
|
|
114319
114661
|
}
|
|
114320
114662
|
|
|
114321
|
-
// src/commands/
|
|
114663
|
+
// src/commands/export.ts
|
|
114322
114664
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
114665
|
+
function registerExportCommands(cli, ctx) {
|
|
114666
|
+
cli.command("export [app]", "Download an export bundle for an app (no secrets)").option("--out <path>", "Where to write the .tar.gz (defaults to ./{name}-{date}.tar.gz)").action(async (app, options) => {
|
|
114667
|
+
const result = await exportApp(ctx, {
|
|
114668
|
+
app,
|
|
114669
|
+
out: options.out,
|
|
114670
|
+
deliveryKind: "cli"
|
|
114671
|
+
});
|
|
114672
|
+
await writeLine(ctx, `${import_picocolors9.default.green("✓")} exported ${result.appName} → ${result.outPath} (${(result.bytes / 1024).toFixed(1)} KB)`);
|
|
114673
|
+
await writeLine(ctx, import_picocolors9.default.dim("Env values are not included. To export encrypted env values, use the dashboard's Settings → Export and confirm your password."));
|
|
114674
|
+
});
|
|
114675
|
+
}
|
|
114676
|
+
|
|
114677
|
+
// src/commands/github.ts
|
|
114678
|
+
var import_picocolors10 = __toESM(require_picocolors(), 1);
|
|
114323
114679
|
async function printWebhookInstructions(ctx, instructions, branch) {
|
|
114324
|
-
await writeLine(ctx,
|
|
114680
|
+
await writeLine(ctx, import_picocolors10.default.bold("Add this webhook in GitHub to enable auto-deploy on push:"));
|
|
114325
114681
|
await writeLine(ctx, ` URL: ${instructions.settingsUrl}`);
|
|
114326
114682
|
await writeLine(ctx, "");
|
|
114327
114683
|
await writeLine(ctx, " Field Value");
|
|
@@ -114331,9 +114687,9 @@ async function printWebhookInstructions(ctx, instructions, branch) {
|
|
|
114331
114687
|
await writeLine(ctx, ` Secret ${instructions.secret}`);
|
|
114332
114688
|
await writeLine(ctx, " Which events? Just the push event");
|
|
114333
114689
|
await writeLine(ctx, "");
|
|
114334
|
-
await writeLine(ctx,
|
|
114690
|
+
await writeLine(ctx, import_picocolors10.default.yellow(" ⚠ Treat this secret like a password — save it now, it won't be shown again."));
|
|
114335
114691
|
await writeLine(ctx, "");
|
|
114336
|
-
await writeLine(ctx,
|
|
114692
|
+
await writeLine(ctx, import_picocolors10.default.dim(`After adding the webhook, every push to ${branch} will auto-deploy.`));
|
|
114337
114693
|
}
|
|
114338
114694
|
function registerGithubCommands(cli, ctx) {
|
|
114339
114695
|
cli.command("github [action] [repoUrl] [...rest]", "GitHub integration: connect | setup-webhook").option("--app <name>", "App name (overrides percher.toml)").option("--branch <branch>", "(connect only) Branch to track (default: main)").action(async (action, repoUrl, _rest, options) => {
|
|
@@ -114346,24 +114702,24 @@ function registerGithubCommands(cli, ctx) {
|
|
|
114346
114702
|
repoUrl,
|
|
114347
114703
|
branch: options.branch
|
|
114348
114704
|
});
|
|
114349
|
-
await writeLine(ctx, `${
|
|
114350
|
-
await writeLine(ctx, `${
|
|
114705
|
+
await writeLine(ctx, `${import_picocolors10.default.green("✓")} Connected to ${result.repoUrl} (branch: ${result.branch})`);
|
|
114706
|
+
await writeLine(ctx, `${import_picocolors10.default.green("✓")} Deploy started: ${result.deployId}`);
|
|
114351
114707
|
await writeLine(ctx, "");
|
|
114352
114708
|
if (result.webhookSetupFailed) {
|
|
114353
|
-
await writeLine(ctx,
|
|
114354
|
-
await writeLine(ctx,
|
|
114355
|
-
await writeLine(ctx, ` ${
|
|
114709
|
+
await writeLine(ctx, import_picocolors10.default.yellow(`⚠ Webhook setup failed: ${result.webhookSetupError ?? "unknown error"}`));
|
|
114710
|
+
await writeLine(ctx, import_picocolors10.default.yellow(" Auto-deploy will NOT work until you re-run webhook setup:"));
|
|
114711
|
+
await writeLine(ctx, ` ${import_picocolors10.default.bold(`percher github setup-webhook${options.app ? ` --app ${options.app}` : ""}`)}`);
|
|
114356
114712
|
return;
|
|
114357
114713
|
}
|
|
114358
114714
|
if (result.webhookInstructions) {
|
|
114359
114715
|
await printWebhookInstructions(ctx, result.webhookInstructions, result.branch);
|
|
114360
114716
|
}
|
|
114361
|
-
await writeLine(ctx,
|
|
114717
|
+
await writeLine(ctx, import_picocolors10.default.dim(`Track the initial deploy: percher deploys inspect ${result.deployId}`));
|
|
114362
114718
|
return;
|
|
114363
114719
|
}
|
|
114364
114720
|
if (action === "setup-webhook") {
|
|
114365
114721
|
const result = await githubSetupWebhook(ctx, { app: options.app });
|
|
114366
|
-
await writeLine(ctx, `${
|
|
114722
|
+
await writeLine(ctx, `${import_picocolors10.default.green("✓")} Webhook regenerated for ${result.app}`);
|
|
114367
114723
|
await writeLine(ctx, "");
|
|
114368
114724
|
await printWebhookInstructions(ctx, result.webhookInstructions, result.branch);
|
|
114369
114725
|
return;
|
|
@@ -114375,17 +114731,17 @@ function registerGithubCommands(cli, ctx) {
|
|
|
114375
114731
|
}
|
|
114376
114732
|
|
|
114377
114733
|
// src/commands/migrate.ts
|
|
114378
|
-
var
|
|
114734
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
114379
114735
|
function registerMigrateCommands(cli, ctx) {
|
|
114380
114736
|
cli.command("migrate-from-supabase", "Migrate a Supabase project to PocketBase (FUTURE9 Phase A read-only + Phase B preview writes)").option("--project <ref>", "Supabase project reference (the 20-char id from the project URL)").option("--token <token>", "Supabase personal access token (sbp_...). Read from SUPABASE_ACCESS_TOKEN if omitted.").option("--inspect-only", "Run schema introspection only (Phase A — read-only, no file writes)").option("--output-dir <dir>", "Where to write the Phase B preview files (default: ./migration-preview/)").option("--json", "Output the structured result as JSON").action(async (options) => {
|
|
114381
114737
|
const projectRef = options.project;
|
|
114382
114738
|
const token = options.token ?? ctx.env.SUPABASE_ACCESS_TOKEN;
|
|
114383
114739
|
if (!projectRef) {
|
|
114384
|
-
await writeLine(ctx, `${
|
|
114740
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} Missing --project. Pass your Supabase project ref (e.g. --project abcdefghijklmnopqrst).`);
|
|
114385
114741
|
throw new SilentExitError(1);
|
|
114386
114742
|
}
|
|
114387
114743
|
if (!token) {
|
|
114388
|
-
await writeLine(ctx, `${
|
|
114744
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} Missing --token. Pass --token sbp_... or set SUPABASE_ACCESS_TOKEN. Generate one at https://supabase.com/dashboard/account/tokens`);
|
|
114389
114745
|
throw new SilentExitError(1);
|
|
114390
114746
|
}
|
|
114391
114747
|
if (options.inspectOnly) {
|
|
@@ -114420,103 +114776,103 @@ function registerMigrateCommands(cli, ctx) {
|
|
|
114420
114776
|
async function renderInspectHuman(ctx, result) {
|
|
114421
114777
|
if (result.status === "failed") {
|
|
114422
114778
|
const err = result.error;
|
|
114423
|
-
await writeLine(ctx, `${
|
|
114779
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} ${err?.title ?? "Inspection failed"}`);
|
|
114424
114780
|
if (err?.explanation)
|
|
114425
114781
|
await writeLine(ctx, ` ${err.explanation}`);
|
|
114426
114782
|
if (err?.suggestion)
|
|
114427
|
-
await writeLine(ctx,
|
|
114783
|
+
await writeLine(ctx, import_picocolors11.default.dim(` ${err.suggestion}`));
|
|
114428
114784
|
return;
|
|
114429
114785
|
}
|
|
114430
|
-
await writeLine(ctx, `${
|
|
114786
|
+
await writeLine(ctx, `${import_picocolors11.default.green("✓")} ${result.summary}`);
|
|
114431
114787
|
await writeLine(ctx, "");
|
|
114432
|
-
await writeLine(ctx,
|
|
114788
|
+
await writeLine(ctx, import_picocolors11.default.bold("Tables"));
|
|
114433
114789
|
if (result.tables.length === 0) {
|
|
114434
|
-
await writeLine(ctx,
|
|
114790
|
+
await writeLine(ctx, import_picocolors11.default.dim(" (none in user schemas)"));
|
|
114435
114791
|
}
|
|
114436
114792
|
for (const table of result.tables) {
|
|
114437
114793
|
const pkCount = table.columns.filter((c) => c.isPrimaryKey).length;
|
|
114438
114794
|
const fkCount = table.columns.filter((c) => c.foreignKey !== null).length;
|
|
114439
114795
|
const policyCount = table.rlsPolicies.length;
|
|
114440
114796
|
const rowEstimate = table.estimatedRowCount.toLocaleString();
|
|
114441
|
-
await writeLine(ctx, ` ${
|
|
114797
|
+
await writeLine(ctx, ` ${import_picocolors11.default.cyan(`${table.schema}.${table.name}`)} ${import_picocolors11.default.dim(`cols=${table.columns.length} pk=${pkCount} fk=${fkCount} rls=${policyCount} rows≈${rowEstimate}`)}`);
|
|
114442
114798
|
}
|
|
114443
114799
|
if (result.storageBuckets.length > 0) {
|
|
114444
114800
|
await writeLine(ctx, "");
|
|
114445
|
-
await writeLine(ctx,
|
|
114801
|
+
await writeLine(ctx, import_picocolors11.default.bold("Storage buckets"));
|
|
114446
114802
|
for (const bucket of result.storageBuckets) {
|
|
114447
114803
|
const visibility = bucket.public ? "public" : "private";
|
|
114448
|
-
await writeLine(ctx, ` ${
|
|
114804
|
+
await writeLine(ctx, ` ${import_picocolors11.default.cyan(bucket.name)} ${import_picocolors11.default.dim(`(${visibility})`)}`);
|
|
114449
114805
|
}
|
|
114450
114806
|
}
|
|
114451
114807
|
if (result.authUsersCount !== null) {
|
|
114452
114808
|
await writeLine(ctx, "");
|
|
114453
|
-
await writeLine(ctx, `${
|
|
114809
|
+
await writeLine(ctx, `${import_picocolors11.default.bold("Auth users")}: ${result.authUsersCount}`);
|
|
114454
114810
|
}
|
|
114455
114811
|
if (result.warnings.length > 0) {
|
|
114456
114812
|
await writeLine(ctx, "");
|
|
114457
|
-
await writeLine(ctx,
|
|
114813
|
+
await writeLine(ctx, import_picocolors11.default.bold(`Warnings (${result.warnings.length})`));
|
|
114458
114814
|
for (const warning of result.warnings) {
|
|
114459
|
-
await writeLine(ctx, ` ${
|
|
114815
|
+
await writeLine(ctx, ` ${import_picocolors11.default.yellow("⚠")} ${warning}`);
|
|
114460
114816
|
}
|
|
114461
114817
|
}
|
|
114462
114818
|
await writeLine(ctx, "");
|
|
114463
|
-
await writeLine(ctx,
|
|
114819
|
+
await writeLine(ctx, import_picocolors11.default.dim("--inspect-only is read-only. Drop the flag to also write the Phase B PocketBase-schema preview."));
|
|
114464
114820
|
}
|
|
114465
114821
|
async function renderSchemaHuman(ctx, result) {
|
|
114466
114822
|
if (result.status === "failed") {
|
|
114467
114823
|
const err = result.error;
|
|
114468
|
-
await writeLine(ctx, `${
|
|
114824
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} ${err?.title ?? "Migration preview failed"}`);
|
|
114469
114825
|
if (err?.explanation)
|
|
114470
114826
|
await writeLine(ctx, ` ${err.explanation}`);
|
|
114471
114827
|
if (err?.suggestion)
|
|
114472
|
-
await writeLine(ctx,
|
|
114828
|
+
await writeLine(ctx, import_picocolors11.default.dim(` ${err.suggestion}`));
|
|
114473
114829
|
return;
|
|
114474
114830
|
}
|
|
114475
|
-
await writeLine(ctx, `${
|
|
114831
|
+
await writeLine(ctx, `${import_picocolors11.default.green("✓")} ${result.summary}`);
|
|
114476
114832
|
await writeLine(ctx, "");
|
|
114477
|
-
await writeLine(ctx,
|
|
114833
|
+
await writeLine(ctx, import_picocolors11.default.bold("Files written"));
|
|
114478
114834
|
for (const path of result.filesWritten) {
|
|
114479
|
-
await writeLine(ctx, ` ${
|
|
114835
|
+
await writeLine(ctx, ` ${import_picocolors11.default.cyan(path)}`);
|
|
114480
114836
|
}
|
|
114481
114837
|
const preview = result.preview;
|
|
114482
114838
|
if (!preview)
|
|
114483
114839
|
return;
|
|
114484
114840
|
if (preview.collections.length > 0) {
|
|
114485
114841
|
await writeLine(ctx, "");
|
|
114486
|
-
await writeLine(ctx,
|
|
114842
|
+
await writeLine(ctx, import_picocolors11.default.bold("Collections"));
|
|
114487
114843
|
for (const collection of preview.collections) {
|
|
114488
114844
|
const fields = collection.schema.length;
|
|
114489
114845
|
const relations = collection.schema.filter((f) => f.type === "relation").length;
|
|
114490
|
-
await writeLine(ctx, ` ${
|
|
114846
|
+
await writeLine(ctx, ` ${import_picocolors11.default.cyan(collection.name)} ${import_picocolors11.default.dim(`← ${collection.sourceTable} fields=${fields} relations=${relations}`)}`);
|
|
114491
114847
|
}
|
|
114492
114848
|
}
|
|
114493
114849
|
if (preview.warnings.length > 0) {
|
|
114494
114850
|
await writeLine(ctx, "");
|
|
114495
|
-
await writeLine(ctx,
|
|
114851
|
+
await writeLine(ctx, import_picocolors11.default.bold(`Warnings (${preview.warnings.length})`));
|
|
114496
114852
|
for (const warning of preview.warnings.slice(0, 10)) {
|
|
114497
|
-
await writeLine(ctx, ` ${
|
|
114853
|
+
await writeLine(ctx, ` ${import_picocolors11.default.yellow("⚠")} ${warning}`);
|
|
114498
114854
|
}
|
|
114499
114855
|
if (preview.warnings.length > 10) {
|
|
114500
|
-
await writeLine(ctx,
|
|
114856
|
+
await writeLine(ctx, import_picocolors11.default.dim(` …and ${preview.warnings.length - 10} more — see MIGRATION_NOTES.md`));
|
|
114501
114857
|
}
|
|
114502
114858
|
}
|
|
114503
114859
|
await writeLine(ctx, "");
|
|
114504
|
-
await writeLine(ctx,
|
|
114860
|
+
await writeLine(ctx, import_picocolors11.default.dim("Phase B is a preview. Phase C (data import) and Phase D (client rewrite) ship in later releases. Review MIGRATION_NOTES.md before any import."));
|
|
114505
114861
|
}
|
|
114506
114862
|
|
|
114507
114863
|
// src/commands/sharing.ts
|
|
114508
|
-
var
|
|
114864
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
114509
114865
|
function registerSharingCommands(cli, ctx) {
|
|
114510
114866
|
cli.command("share [action] [arg] [valueOrRole]", "Per-app collaborator invites: list | invite <email> | role <shareId> <role> | revoke <shareId>").option("--app <name>", "App name (overrides percher.toml)").option("--role <role>", "(invite only) viewer | admin — viewer is read-only, admin can deploy + change config").action(async (action, arg, valueOrRole, options) => {
|
|
114511
114867
|
if (action === "list" || action === undefined) {
|
|
114512
114868
|
const rows = await shareList(ctx, { app: options.app });
|
|
114513
114869
|
if (rows.length === 0) {
|
|
114514
|
-
await writeLine(ctx,
|
|
114870
|
+
await writeLine(ctx, import_picocolors12.default.dim("No collaborators."));
|
|
114515
114871
|
return;
|
|
114516
114872
|
}
|
|
114517
114873
|
for (const r of rows) {
|
|
114518
|
-
const state = r.accepted ?
|
|
114519
|
-
const roleStr = r.role === "admin" ?
|
|
114874
|
+
const state = r.accepted ? import_picocolors12.default.green("accepted") : import_picocolors12.default.yellow("pending");
|
|
114875
|
+
const roleStr = r.role === "admin" ? import_picocolors12.default.cyan("admin") : import_picocolors12.default.dim("viewer");
|
|
114520
114876
|
await writeLine(ctx, `${r.id} ${roleStr.padEnd(15)} ${state.padEnd(15)} ${r.email}`);
|
|
114521
114877
|
}
|
|
114522
114878
|
return;
|
|
@@ -114534,8 +114890,8 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114534
114890
|
email: arg,
|
|
114535
114891
|
role: roleRaw
|
|
114536
114892
|
});
|
|
114537
|
-
await writeLine(ctx, `${
|
|
114538
|
-
await writeLine(ctx,
|
|
114893
|
+
await writeLine(ctx, `${import_picocolors12.default.green("✓")} Invited ${created.email} as ${created.role} (id ${created.id})`);
|
|
114894
|
+
await writeLine(ctx, import_picocolors12.default.dim(`Pending until accepted — invite expires ${new Date(created.expiresAt).toLocaleDateString()}.`));
|
|
114539
114895
|
return;
|
|
114540
114896
|
}
|
|
114541
114897
|
if (action === "role") {
|
|
@@ -114550,7 +114906,7 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114550
114906
|
shareId: arg,
|
|
114551
114907
|
role: valueOrRole
|
|
114552
114908
|
});
|
|
114553
|
-
await writeLine(ctx, `${
|
|
114909
|
+
await writeLine(ctx, `${import_picocolors12.default.green("✓")} ${updated.email} is now ${import_picocolors12.default.cyan(updated.role)}`);
|
|
114554
114910
|
return;
|
|
114555
114911
|
}
|
|
114556
114912
|
if (action === "revoke") {
|
|
@@ -114558,7 +114914,7 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114558
114914
|
throw new Error("Usage: percher share revoke <shareId> [--app <name>]");
|
|
114559
114915
|
}
|
|
114560
114916
|
await shareRevoke(ctx, { app: options.app, shareId: arg });
|
|
114561
|
-
await writeLine(ctx, `${
|
|
114917
|
+
await writeLine(ctx, `${import_picocolors12.default.green("✓")} Revoked share ${arg}`);
|
|
114562
114918
|
return;
|
|
114563
114919
|
}
|
|
114564
114920
|
throw new Error(`Unknown share action "${action}". Use list | invite <email> | role <shareId> <role> | revoke <shareId>.`);
|
|
@@ -114571,11 +114927,11 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114571
114927
|
if (action === undefined || action === "list") {
|
|
114572
114928
|
const pending = await invitesList(ctx, {});
|
|
114573
114929
|
if (pending.length === 0) {
|
|
114574
|
-
await writeLine(ctx,
|
|
114930
|
+
await writeLine(ctx, import_picocolors12.default.dim("No pending invites."));
|
|
114575
114931
|
return;
|
|
114576
114932
|
}
|
|
114577
114933
|
for (const inv of pending) {
|
|
114578
|
-
const roleStr = inv.role === "admin" ?
|
|
114934
|
+
const roleStr = inv.role === "admin" ? import_picocolors12.default.cyan("admin") : import_picocolors12.default.dim("viewer");
|
|
114579
114935
|
await writeLine(ctx, `${inv.id} ${roleStr.padEnd(15)} ${inv.appName.padEnd(24)} from ${inv.invitedBy}`);
|
|
114580
114936
|
}
|
|
114581
114937
|
return;
|
|
@@ -114586,10 +114942,10 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114586
114942
|
}
|
|
114587
114943
|
const accepted = await invitesAccept(ctx, { shareId });
|
|
114588
114944
|
if (accepted.alreadyAccepted) {
|
|
114589
|
-
await writeLine(ctx,
|
|
114945
|
+
await writeLine(ctx, import_picocolors12.default.dim(`Invite ${shareId} was already accepted.`));
|
|
114590
114946
|
return;
|
|
114591
114947
|
}
|
|
114592
|
-
await writeLine(ctx, `${
|
|
114948
|
+
await writeLine(ctx, `${import_picocolors12.default.green("✓")} Accepted — you now have ${import_picocolors12.default.cyan(accepted.role)} access to the shared app.`);
|
|
114593
114949
|
return;
|
|
114594
114950
|
}
|
|
114595
114951
|
if (action === "decline") {
|
|
@@ -114597,7 +114953,7 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114597
114953
|
throw new Error("Usage: percher invites decline <shareId>");
|
|
114598
114954
|
}
|
|
114599
114955
|
await invitesDecline(ctx, { shareId });
|
|
114600
|
-
await writeLine(ctx, `${
|
|
114956
|
+
await writeLine(ctx, `${import_picocolors12.default.green("✓")} Declined invite ${shareId}.`);
|
|
114601
114957
|
return;
|
|
114602
114958
|
}
|
|
114603
114959
|
throw new Error(`Unknown invites action "${action}". Use list | accept <shareId> | decline <shareId>.`);
|
|
@@ -114608,7 +114964,7 @@ function registerSharingCommands(cli, ctx) {
|
|
|
114608
114964
|
}
|
|
114609
114965
|
|
|
114610
114966
|
// src/commands/status.ts
|
|
114611
|
-
var
|
|
114967
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
114612
114968
|
function registerStatusCommands(cli, ctx) {
|
|
114613
114969
|
cli.command("status", "Show Percher platform status (API + worker health)").option("--json", "Output JSON instead of formatted text").action(async (options) => {
|
|
114614
114970
|
const result = await status(ctx, { json: Boolean(options.json) });
|
|
@@ -114624,44 +114980,44 @@ function registerStatusCommands(cli, ctx) {
|
|
|
114624
114980
|
});
|
|
114625
114981
|
}
|
|
114626
114982
|
async function renderHumanStatus(ctx, result) {
|
|
114627
|
-
const symbol2 = result.verdict === "operational" ?
|
|
114983
|
+
const symbol2 = result.verdict === "operational" ? import_picocolors13.default.green("✓") : result.verdict === "worker-degraded" ? import_picocolors13.default.yellow("⚠") : import_picocolors13.default.red("✗");
|
|
114628
114984
|
await writeLine(ctx, `${symbol2} ${result.summary}`);
|
|
114629
114985
|
if (!result.health)
|
|
114630
114986
|
return;
|
|
114631
114987
|
const worker = result.health.worker;
|
|
114632
114988
|
if (!worker) {
|
|
114633
|
-
await writeLine(ctx,
|
|
114989
|
+
await writeLine(ctx, import_picocolors13.default.dim(" worker: not configured (local Docker socket)"));
|
|
114634
114990
|
return;
|
|
114635
114991
|
}
|
|
114636
114992
|
if (worker.health) {
|
|
114637
114993
|
const ok = worker.health.ok;
|
|
114638
|
-
const symbol3 = ok ?
|
|
114994
|
+
const symbol3 = ok ? import_picocolors13.default.green("✓") : import_picocolors13.default.red("✗");
|
|
114639
114995
|
const lastOk = worker.health.lastOkAt ?? "never";
|
|
114640
|
-
await writeLine(ctx, ` ${symbol3} worker health: ${ok ? "ok" : `failing (${worker.health.consecutiveErrs} consecutive)`} last-ok=${
|
|
114996
|
+
await writeLine(ctx, ` ${symbol3} worker health: ${ok ? "ok" : `failing (${worker.health.consecutiveErrs} consecutive)`} last-ok=${import_picocolors13.default.dim(lastOk)}`);
|
|
114641
114997
|
}
|
|
114642
114998
|
if (worker.circuitBreaker) {
|
|
114643
114999
|
const breaker = worker.circuitBreaker;
|
|
114644
|
-
const symbol3 = breaker.open ?
|
|
115000
|
+
const symbol3 = breaker.open ? import_picocolors13.default.red("✗") : import_picocolors13.default.green("✓");
|
|
114645
115001
|
const state = breaker.open ? "open (deploys fail fast)" : "closed";
|
|
114646
115002
|
await writeLine(ctx, ` ${symbol3} circuit breaker: ${state} ${breaker.failuresInWindow}/${breaker.threshold} failures in last ${Math.round(breaker.windowMs / 1000)}s`);
|
|
114647
115003
|
}
|
|
114648
115004
|
if (result.health.version) {
|
|
114649
|
-
await writeLine(ctx,
|
|
115005
|
+
await writeLine(ctx, import_picocolors13.default.dim(` api version: ${result.health.version}`));
|
|
114650
115006
|
}
|
|
114651
115007
|
}
|
|
114652
115008
|
|
|
114653
115009
|
// src/commands/transfers.ts
|
|
114654
|
-
var
|
|
115010
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
114655
115011
|
function registerTransfersCommands(cli, ctx) {
|
|
114656
115012
|
cli.command("transfer [emailOrTransferId]", "Transfer ownership of an app: `transfer <email>` initiates; `transfer --cancel <id>` cancels; `transfer --list` shows history").option("--app <name>", "App name (overrides percher.toml)").option("--cancel", "Cancel a pending transfer by id (positional arg is the transferId)").option("--list", "List the transfer history for this app").action(async (emailOrTransferId, options) => {
|
|
114657
115013
|
if (options.list) {
|
|
114658
115014
|
const rows = await transferListForApp(ctx, { app: options.app });
|
|
114659
115015
|
if (rows.length === 0) {
|
|
114660
|
-
await writeLine(ctx,
|
|
115016
|
+
await writeLine(ctx, import_picocolors14.default.dim("No transfers for this app."));
|
|
114661
115017
|
return;
|
|
114662
115018
|
}
|
|
114663
115019
|
for (const r of rows) {
|
|
114664
|
-
const status2 = r.status === "pending" ?
|
|
115020
|
+
const status2 = r.status === "pending" ? import_picocolors14.default.yellow("pending") : r.status === "accepted" ? import_picocolors14.default.green("accepted") : import_picocolors14.default.dim(r.status);
|
|
114665
115021
|
await writeLine(ctx, `${r.id} ${status2.padEnd(20)} → ${r.toEmail} (${r.createdAt})`);
|
|
114666
115022
|
}
|
|
114667
115023
|
return;
|
|
@@ -114674,7 +115030,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
114674
115030
|
app: options.app,
|
|
114675
115031
|
transferId: emailOrTransferId
|
|
114676
115032
|
});
|
|
114677
|
-
await writeLine(ctx, `${
|
|
115033
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} Cancelled transfer ${emailOrTransferId}`);
|
|
114678
115034
|
return;
|
|
114679
115035
|
}
|
|
114680
115036
|
if (!emailOrTransferId) {
|
|
@@ -114684,17 +115040,17 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
114684
115040
|
app: options.app,
|
|
114685
115041
|
email: emailOrTransferId
|
|
114686
115042
|
});
|
|
114687
|
-
await writeLine(ctx, `${
|
|
114688
|
-
await writeLine(ctx,
|
|
115043
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} Transfer initiated to ${initiated.toEmail} (id ${initiated.id})`);
|
|
115044
|
+
await writeLine(ctx, import_picocolors14.default.dim(`Expires ${new Date(initiated.expiresAt).toLocaleDateString()}. The recipient must accept via 'percher transfers accept ${initiated.id}'.`));
|
|
114689
115045
|
if (initiated.notes) {
|
|
114690
|
-
await writeLine(ctx,
|
|
115046
|
+
await writeLine(ctx, import_picocolors14.default.yellow(` ⚠ ${initiated.notes}`));
|
|
114691
115047
|
}
|
|
114692
115048
|
});
|
|
114693
115049
|
cli.command("transfers [action] [transferId]", "Incoming ownership transfers: list (default) | accept <transferId> | decline <transferId>").action(async (action, transferId) => {
|
|
114694
115050
|
if (action === undefined || action === "list") {
|
|
114695
115051
|
const rows = await transfersIncoming(ctx, {});
|
|
114696
115052
|
if (rows.length === 0) {
|
|
114697
|
-
await writeLine(ctx,
|
|
115053
|
+
await writeLine(ctx, import_picocolors14.default.dim("No pending incoming transfers."));
|
|
114698
115054
|
return;
|
|
114699
115055
|
}
|
|
114700
115056
|
for (const r of rows) {
|
|
@@ -114707,7 +115063,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
114707
115063
|
throw new Error("Usage: percher transfers accept <transferId>");
|
|
114708
115064
|
}
|
|
114709
115065
|
const accepted = await transfersAccept(ctx, { transferId });
|
|
114710
|
-
await writeLine(ctx, `${
|
|
115066
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} You now own ${import_picocolors14.default.cyan(accepted.appName)}. Run 'percher open --app ${accepted.appName}' to see it.`);
|
|
114711
115067
|
return;
|
|
114712
115068
|
}
|
|
114713
115069
|
if (action === "decline") {
|
|
@@ -114715,7 +115071,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
114715
115071
|
throw new Error("Usage: percher transfers decline <transferId>");
|
|
114716
115072
|
}
|
|
114717
115073
|
await transfersDecline(ctx, { transferId });
|
|
114718
|
-
await writeLine(ctx, `${
|
|
115074
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} Declined transfer ${transferId}.`);
|
|
114719
115075
|
return;
|
|
114720
115076
|
}
|
|
114721
115077
|
throw new Error(`Unknown transfers action "${action}". Use list | accept <id> | decline <id>.`);
|
|
@@ -114784,40 +115140,52 @@ async function createCliContext() {
|
|
|
114784
115140
|
}
|
|
114785
115141
|
|
|
114786
115142
|
// src/output.ts
|
|
114787
|
-
var
|
|
115143
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
114788
115144
|
async function renderError(stderr, error48) {
|
|
114789
115145
|
const writer = stderr.getWriter();
|
|
114790
115146
|
const encoder = new TextEncoder;
|
|
114791
115147
|
const lines = [];
|
|
114792
115148
|
if (error48 instanceof PercherTomlError) {
|
|
114793
|
-
lines.push(`${
|
|
115149
|
+
lines.push(`${import_picocolors15.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
114794
115150
|
if (error48.tomlLine !== undefined) {
|
|
114795
|
-
lines.push(
|
|
115151
|
+
lines.push(import_picocolors15.default.dim(` at percher.toml line ${error48.tomlLine}`));
|
|
114796
115152
|
}
|
|
114797
115153
|
for (const issue2 of error48.issues ?? []) {
|
|
114798
|
-
lines.push(`${
|
|
115154
|
+
lines.push(`${import_picocolors15.default.dim(" · ") + import_picocolors15.default.yellow(issue2.path.join("."))}: ${issue2.message}`);
|
|
115155
|
+
}
|
|
115156
|
+
} else if (error48 instanceof SunsetError) {
|
|
115157
|
+
if (error48.gateCode === "platform_delete_gated") {
|
|
115158
|
+
lines.push(`${import_picocolors15.default.yellow("Percher is shutting down — deletes are paused.")}`);
|
|
115159
|
+
lines.push(error48.message);
|
|
115160
|
+
lines.push(import_picocolors15.default.dim(` To delete and permanently forfeit your export window, confirm with your password in the dashboard: ${error48.dashboardUrl}`));
|
|
115161
|
+
lines.push(import_picocolors15.default.dim(" The CLI cannot perform this delete during sunset — it must go through the dashboard."));
|
|
115162
|
+
} else {
|
|
115163
|
+
lines.push(`${import_picocolors15.default.yellow("Percher is in read-only mode ahead of shutdown.")}`);
|
|
115164
|
+
lines.push(error48.message);
|
|
115165
|
+
lines.push(import_picocolors15.default.dim(` Your apps keep running. Export them any time from the dashboard: ${error48.dashboardUrl}`));
|
|
114799
115166
|
}
|
|
115167
|
+
lines.push(import_picocolors15.default.dim(` Final data deletion: ${error48.finalDeletionDate}`));
|
|
114800
115168
|
} else if (error48 instanceof PercherApiError) {
|
|
114801
115169
|
if (error48.status === 502 || error48.status === 503) {
|
|
114802
|
-
lines.push(`${
|
|
115170
|
+
lines.push(`${import_picocolors15.default.red("error:")} Percher API is temporarily unavailable (HTTP ${error48.status}). Try again in a few seconds.`);
|
|
114803
115171
|
} else {
|
|
114804
|
-
lines.push(`${
|
|
114805
|
-
lines.push(
|
|
115172
|
+
lines.push(`${import_picocolors15.default.red("error:")} ${error48.message}`);
|
|
115173
|
+
lines.push(import_picocolors15.default.dim(` ${error48.code} (HTTP ${error48.status})`));
|
|
114806
115174
|
}
|
|
114807
115175
|
if (error48.requestId)
|
|
114808
|
-
lines.push(
|
|
115176
|
+
lines.push(import_picocolors15.default.dim(` request: ${error48.requestId}`));
|
|
114809
115177
|
} else if (error48 instanceof PercherCoreError) {
|
|
114810
|
-
lines.push(`${
|
|
115178
|
+
lines.push(`${import_picocolors15.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
114811
115179
|
if (error48.hint)
|
|
114812
|
-
lines.push(
|
|
115180
|
+
lines.push(import_picocolors15.default.dim(` ${error48.hint}`));
|
|
114813
115181
|
} else if (error48 instanceof Error) {
|
|
114814
|
-
lines.push(`${
|
|
115182
|
+
lines.push(`${import_picocolors15.default.red("unexpected error:")} ${error48.message}`);
|
|
114815
115183
|
if (error48.stack)
|
|
114816
|
-
lines.push(
|
|
115184
|
+
lines.push(import_picocolors15.default.dim(error48.stack.split(`
|
|
114817
115185
|
`).slice(1, 4).join(`
|
|
114818
115186
|
`)));
|
|
114819
115187
|
} else {
|
|
114820
|
-
lines.push(`${
|
|
115188
|
+
lines.push(`${import_picocolors15.default.red("unexpected error:")} ${String(error48)}`);
|
|
114821
115189
|
}
|
|
114822
115190
|
try {
|
|
114823
115191
|
await writer.write(encoder.encode(`${lines.join(`
|
|
@@ -114830,7 +115198,7 @@ async function renderError(stderr, error48) {
|
|
|
114830
115198
|
// package.json
|
|
114831
115199
|
var package_default = {
|
|
114832
115200
|
name: "percher",
|
|
114833
|
-
version: "0.4.
|
|
115201
|
+
version: "0.4.2",
|
|
114834
115202
|
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
114835
115203
|
type: "module",
|
|
114836
115204
|
bin: {
|
|
@@ -114927,7 +115295,7 @@ async function showTelemetryNotice() {
|
|
|
114927
115295
|
}
|
|
114928
115296
|
|
|
114929
115297
|
// src/version-check.ts
|
|
114930
|
-
var
|
|
115298
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
114931
115299
|
async function checkForUpdates() {
|
|
114932
115300
|
try {
|
|
114933
115301
|
const res = await fetch("https://registry.npmjs.org/percher/latest", {
|
|
@@ -114938,9 +115306,9 @@ async function checkForUpdates() {
|
|
|
114938
115306
|
const data2 = await res.json();
|
|
114939
115307
|
const latest = data2.version;
|
|
114940
115308
|
if (latest && latest !== VERSION) {
|
|
114941
|
-
console.error(
|
|
115309
|
+
console.error(import_picocolors16.default.yellow(`
|
|
114942
115310
|
Update available: ${VERSION} → ${latest}`));
|
|
114943
|
-
console.error(
|
|
115311
|
+
console.error(import_picocolors16.default.dim(`Run: bunx percher@latest
|
|
114944
115312
|
`));
|
|
114945
115313
|
}
|
|
114946
115314
|
} catch {}
|
|
@@ -114953,6 +115321,7 @@ async function run(argv, ctxOverride) {
|
|
|
114953
115321
|
registerAppsCommands(cli, ctx);
|
|
114954
115322
|
registerDeploysCommands(cli, ctx, argv);
|
|
114955
115323
|
registerEnvCommands(cli, ctx);
|
|
115324
|
+
registerExportCommands(cli, ctx);
|
|
114956
115325
|
registerDataCommands(cli, ctx, argv);
|
|
114957
115326
|
registerAuthCommands(cli, ctx);
|
|
114958
115327
|
registerAccountCommands(cli, ctx);
|