percher 1.1.0 → 1.3.0
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 +1903 -972
- package/dist/package.json +4 -4
- package/dist/src/cli-utils.d.ts +1 -0
- package/dist/src/cli-utils.d.ts.map +1 -1
- package/dist/src/cli-utils.js +9 -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 -14
- package/dist/src/commands/apps.js.map +1 -1
- package/dist/src/commands/data-records.d.ts +20 -0
- package/dist/src/commands/data-records.d.ts.map +1 -0
- package/dist/src/commands/data-records.js +183 -0
- package/dist/src/commands/data-records.js.map +1 -0
- package/dist/src/commands/data.d.ts.map +1 -1
- package/dist/src/commands/data.js +18 -2
- package/dist/src/commands/data.js.map +1 -1
- package/dist/src/commands/deploys.d.ts.map +1 -1
- package/dist/src/commands/deploys.js +9 -1
- package/dist/src/commands/deploys.js.map +1 -1
- package/dist/src/commands/telemetry.d.ts +4 -0
- package/dist/src/commands/telemetry.d.ts.map +1 -0
- package/dist/src/commands/telemetry.js +27 -0
- package/dist/src/commands/telemetry.js.map +1 -0
- package/dist/src/index.d.ts +6 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/telemetry.d.ts +28 -3
- package/dist/src/telemetry.d.ts.map +1 -1
- package/dist/src/telemetry.js +107 -24
- package/dist/src/telemetry.js.map +1 -1
- package/dist/templates/astro/Dockerfile +10 -4
- package/dist/templates/capsule/Dockerfile +10 -4
- package/dist/templates/eleventy/Dockerfile +10 -4
- package/dist/templates/hugo/Dockerfile +10 -4
- package/dist/templates/preact/Dockerfile +10 -4
- package/dist/templates/solid/Dockerfile +10 -4
- package/dist/templates/vite-react/Dockerfile +10 -4
- package/dist/templates/vite-vue/Dockerfile +10 -4
- package/package.json +4 -4
package/dist/bin/percher.js
CHANGED
|
@@ -4751,7 +4751,7 @@ var init_build_env_prefixes = __esm(() => {
|
|
|
4751
4751
|
});
|
|
4752
4752
|
|
|
4753
4753
|
// ../client/dist/config.js
|
|
4754
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync4 } from "node:fs";
|
|
4754
|
+
import { chmodSync, closeSync, existsSync as existsSync4, fchmodSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync4, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
4755
4755
|
import { homedir } from "node:os";
|
|
4756
4756
|
import { dirname as dirname4, join as join6 } from "node:path";
|
|
4757
4757
|
function home() {
|
|
@@ -4800,12 +4800,32 @@ function readAnonClaims() {
|
|
|
4800
4800
|
}
|
|
4801
4801
|
function saveConfig(partial2) {
|
|
4802
4802
|
const p = configPath();
|
|
4803
|
-
mkdirSync4(dirname4(p), { recursive: true });
|
|
4803
|
+
mkdirSync4(dirname4(p), { recursive: true, mode: 448 });
|
|
4804
|
+
if (process.platform !== "win32") {
|
|
4805
|
+
chmodSync(dirname4(p), 448);
|
|
4806
|
+
if (existsSync4(p))
|
|
4807
|
+
chmodSync(p, 384);
|
|
4808
|
+
}
|
|
4804
4809
|
const current = readFile2();
|
|
4805
4810
|
const merged = { ...current, ...partial2 };
|
|
4806
4811
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
4807
|
-
|
|
4808
|
-
|
|
4812
|
+
let fd;
|
|
4813
|
+
let created = false;
|
|
4814
|
+
try {
|
|
4815
|
+
fd = openSync(tmp, "wx", 384);
|
|
4816
|
+
created = true;
|
|
4817
|
+
if (process.platform !== "win32")
|
|
4818
|
+
fchmodSync(fd, 384);
|
|
4819
|
+
writeFileSync4(fd, JSON.stringify(merged, null, 2), "utf8");
|
|
4820
|
+
closeSync(fd);
|
|
4821
|
+
fd = undefined;
|
|
4822
|
+
renameSync(tmp, p);
|
|
4823
|
+
} finally {
|
|
4824
|
+
if (fd !== undefined)
|
|
4825
|
+
closeSync(fd);
|
|
4826
|
+
if (created)
|
|
4827
|
+
rmSync2(tmp, { force: true });
|
|
4828
|
+
}
|
|
4809
4829
|
}
|
|
4810
4830
|
function getAnonClaim(app) {
|
|
4811
4831
|
return readAnonClaims()[app] ?? null;
|
|
@@ -4830,7 +4850,7 @@ var package_default;
|
|
|
4830
4850
|
var init_package = __esm(() => {
|
|
4831
4851
|
package_default = {
|
|
4832
4852
|
name: "@percher/client",
|
|
4833
|
-
version: "1.
|
|
4853
|
+
version: "1.3.0",
|
|
4834
4854
|
description: "Official TypeScript SDK for Percher: deploy apps, manage env vars, stream logs, and automate hosting workflows.",
|
|
4835
4855
|
keywords: [
|
|
4836
4856
|
"percher",
|
|
@@ -4871,7 +4891,7 @@ var init_package = __esm(() => {
|
|
|
4871
4891
|
typecheck: "tsc --noEmit"
|
|
4872
4892
|
},
|
|
4873
4893
|
dependencies: {
|
|
4874
|
-
"@percher/toml": "^1.0.
|
|
4894
|
+
"@percher/toml": "^1.0.4"
|
|
4875
4895
|
},
|
|
4876
4896
|
devDependencies: {
|
|
4877
4897
|
"bun-types": "^1.1.0",
|
|
@@ -5384,10 +5404,11 @@ class AppsResource {
|
|
|
5384
5404
|
deleteIconImage(appRef) {
|
|
5385
5405
|
return this.http.deleteJson(`/apps/${encodeURIComponent(appRef)}/icon/image`);
|
|
5386
5406
|
}
|
|
5387
|
-
uploadPreviewImage(appRef, bytes, mime) {
|
|
5407
|
+
uploadPreviewImage(appRef, bytes, mime, orientation) {
|
|
5388
5408
|
const ab = new ArrayBuffer(bytes.byteLength);
|
|
5389
5409
|
new Uint8Array(ab).set(bytes);
|
|
5390
|
-
|
|
5410
|
+
const query = orientation ? `?orientation=${orientation}` : "";
|
|
5411
|
+
return this.http.postBinary(`/apps/${encodeURIComponent(appRef)}/preview/image${query}`, new Blob([ab]), { "Content-Type": mime });
|
|
5391
5412
|
}
|
|
5392
5413
|
deletePreviewImage(appRef) {
|
|
5393
5414
|
return this.http.deleteJson(`/apps/${encodeURIComponent(appRef)}/preview/image`);
|
|
@@ -5642,6 +5663,58 @@ class BillingResource {
|
|
|
5642
5663
|
}
|
|
5643
5664
|
}
|
|
5644
5665
|
|
|
5666
|
+
// ../client/dist/resources/data-records.js
|
|
5667
|
+
function dataPathSegment(kind, value) {
|
|
5668
|
+
const re = kind === "collection" ? COLLECTION_RE : RECORD_ID_RE;
|
|
5669
|
+
if (!re.test(value))
|
|
5670
|
+
throw new TypeError(`invalid data ${kind}`);
|
|
5671
|
+
return encodeURIComponent(value);
|
|
5672
|
+
}
|
|
5673
|
+
function outcomeUnknown(cause, observed) {
|
|
5674
|
+
const answered = cause instanceof PercherApiError;
|
|
5675
|
+
return new PercherApiError(OUTCOME_UNKNOWN_MESSAGE, {
|
|
5676
|
+
status: answered ? cause.status : 0,
|
|
5677
|
+
code: "DATA_WRITE_OUTCOME_UNKNOWN",
|
|
5678
|
+
requestId: answered ? cause.requestId : undefined,
|
|
5679
|
+
cause,
|
|
5680
|
+
extra: { observed }
|
|
5681
|
+
});
|
|
5682
|
+
}
|
|
5683
|
+
function isRecordReply(reply) {
|
|
5684
|
+
return typeof reply === "object" && reply !== null && !Array.isArray(reply) && typeof reply.id === "string" && reply.id.length > 0;
|
|
5685
|
+
}
|
|
5686
|
+
function isDeleteReply(reply) {
|
|
5687
|
+
return reply === undefined || typeof reply === "object" && reply !== null && !Array.isArray(reply);
|
|
5688
|
+
}
|
|
5689
|
+
async function writeOnce(run, usable) {
|
|
5690
|
+
let reply;
|
|
5691
|
+
try {
|
|
5692
|
+
reply = await run();
|
|
5693
|
+
} catch (err) {
|
|
5694
|
+
if (err instanceof SunsetError)
|
|
5695
|
+
throw err;
|
|
5696
|
+
if (err instanceof PercherApiError) {
|
|
5697
|
+
if (err.code === "DATA_WRITE_OUTCOME_UNKNOWN")
|
|
5698
|
+
throw err;
|
|
5699
|
+
if (err.status >= 400 && err.status < 500)
|
|
5700
|
+
throw err;
|
|
5701
|
+
if (err.status >= 500 && WRITE_NOT_SENT.has(err.code))
|
|
5702
|
+
throw err;
|
|
5703
|
+
}
|
|
5704
|
+
throw outcomeUnknown(err, err instanceof PercherApiError ? "error_response" : "no_usable_response");
|
|
5705
|
+
}
|
|
5706
|
+
if (!usable(reply))
|
|
5707
|
+
throw outcomeUnknown(undefined, "unusable_reply");
|
|
5708
|
+
return reply;
|
|
5709
|
+
}
|
|
5710
|
+
var COLLECTION_RE, RECORD_ID_RE, WRITE_NOT_SENT, OUTCOME_UNKNOWN_MESSAGE = "No usable answer arrived for this write, so it may or may not have been saved.";
|
|
5711
|
+
var init_data_records = __esm(() => {
|
|
5712
|
+
init_errors();
|
|
5713
|
+
COLLECTION_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
|
|
5714
|
+
RECORD_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
5715
|
+
WRITE_NOT_SENT = new Set(["PB_NOT_RUNNING", "PB_AUTH_FAILED", "PB_VERSION_UNSUPPORTED"]);
|
|
5716
|
+
});
|
|
5717
|
+
|
|
5645
5718
|
// ../client/dist/resources/data.js
|
|
5646
5719
|
class DataResource {
|
|
5647
5720
|
http;
|
|
@@ -5678,7 +5751,37 @@ class DataResource {
|
|
|
5678
5751
|
removeOAuthProvider(appRef, provider) {
|
|
5679
5752
|
return this.http.delete(`/apps/${encodeURIComponent(appRef)}/data/oauth/${encodeURIComponent(provider)}`);
|
|
5680
5753
|
}
|
|
5754
|
+
getSchema(appRef) {
|
|
5755
|
+
return this.http.get(`/apps/${encodeURIComponent(appRef)}/data/schema`);
|
|
5756
|
+
}
|
|
5757
|
+
queryRecords(appRef, collection, query = {}) {
|
|
5758
|
+
return this.http.post(`${this.records(appRef, collection)}/query`, query);
|
|
5759
|
+
}
|
|
5760
|
+
getRecord(appRef, collection, id) {
|
|
5761
|
+
return this.http.get(this.record(appRef, collection, id));
|
|
5762
|
+
}
|
|
5763
|
+
createRecord(appRef, collection, input) {
|
|
5764
|
+
const path = this.records(appRef, collection);
|
|
5765
|
+
return writeOnce(() => this.http.post(path, input), isRecordReply);
|
|
5766
|
+
}
|
|
5767
|
+
updateRecord(appRef, collection, id, input) {
|
|
5768
|
+
const path = this.record(appRef, collection, id);
|
|
5769
|
+
return writeOnce(() => this.http.patch(path, input), isRecordReply);
|
|
5770
|
+
}
|
|
5771
|
+
async deleteRecord(appRef, collection, id) {
|
|
5772
|
+
const path = this.record(appRef, collection, id);
|
|
5773
|
+
await writeOnce(() => this.http.deleteJson(path), isDeleteReply);
|
|
5774
|
+
}
|
|
5775
|
+
records(appRef, collection) {
|
|
5776
|
+
return `/apps/${encodeURIComponent(appRef)}/data/collections/${dataPathSegment("collection", collection)}/records`;
|
|
5777
|
+
}
|
|
5778
|
+
record(appRef, collection, id) {
|
|
5779
|
+
return `${this.records(appRef, collection)}/${dataPathSegment("id", id)}`;
|
|
5780
|
+
}
|
|
5681
5781
|
}
|
|
5782
|
+
var init_data = __esm(() => {
|
|
5783
|
+
init_data_records();
|
|
5784
|
+
});
|
|
5682
5785
|
|
|
5683
5786
|
// ../client/dist/resources/env.js
|
|
5684
5787
|
function scopeQuery(opts) {
|
|
@@ -6142,6 +6245,7 @@ var init_client = __esm(() => {
|
|
|
6142
6245
|
init_http();
|
|
6143
6246
|
init_apps();
|
|
6144
6247
|
init_auth();
|
|
6248
|
+
init_data();
|
|
6145
6249
|
init_logs();
|
|
6146
6250
|
});
|
|
6147
6251
|
|
|
@@ -6262,6 +6366,55 @@ var init_env_file = __esm(() => {
|
|
|
6262
6366
|
};
|
|
6263
6367
|
});
|
|
6264
6368
|
|
|
6369
|
+
// ../client/dist/telemetry-consent.js
|
|
6370
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
6371
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
6372
|
+
function consentPath() {
|
|
6373
|
+
return join7(dirname5(configPath()), "telemetry.json");
|
|
6374
|
+
}
|
|
6375
|
+
function envOptOut() {
|
|
6376
|
+
if (process.env.PERCHER_NO_TELEMETRY === "1" || process.env.PERCHER_NO_TELEMETRY === "true") {
|
|
6377
|
+
return "PERCHER_NO_TELEMETRY";
|
|
6378
|
+
}
|
|
6379
|
+
if (process.env.DO_NOT_TRACK === "1")
|
|
6380
|
+
return "DO_NOT_TRACK";
|
|
6381
|
+
return null;
|
|
6382
|
+
}
|
|
6383
|
+
function readStored() {
|
|
6384
|
+
try {
|
|
6385
|
+
const parsed = JSON.parse(readFileSync5(consentPath(), "utf8"));
|
|
6386
|
+
if (typeof parsed?.enabled === "boolean" && typeof parsed.decidedAt === "string" && typeof parsed.version === "string") {
|
|
6387
|
+
return { enabled: parsed.enabled, decidedAt: parsed.decidedAt, version: parsed.version };
|
|
6388
|
+
}
|
|
6389
|
+
} catch {}
|
|
6390
|
+
return null;
|
|
6391
|
+
}
|
|
6392
|
+
function telemetryState() {
|
|
6393
|
+
const optOut = envOptOut();
|
|
6394
|
+
const stored = readStored();
|
|
6395
|
+
return { enabled: optOut === null && stored?.enabled === true, envOptOut: optOut, stored };
|
|
6396
|
+
}
|
|
6397
|
+
function saveTelemetryAnswer(enabled, version2) {
|
|
6398
|
+
const p = consentPath();
|
|
6399
|
+
mkdirSync5(dirname5(p), { recursive: true, mode: 448 });
|
|
6400
|
+
if (process.platform !== "win32")
|
|
6401
|
+
chmodSync2(dirname5(p), 448);
|
|
6402
|
+
const answer = { enabled, decidedAt: new Date().toISOString(), version: version2 };
|
|
6403
|
+
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
6404
|
+
try {
|
|
6405
|
+
writeFileSync5(tmp, `${JSON.stringify(answer, null, 2)}
|
|
6406
|
+
`, { mode: 384, flag: "wx" });
|
|
6407
|
+
if (process.platform !== "win32")
|
|
6408
|
+
chmodSync2(tmp, 384);
|
|
6409
|
+
renameSync2(tmp, p);
|
|
6410
|
+
} finally {
|
|
6411
|
+
rmSync3(tmp, { force: true });
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
var init_telemetry_consent = __esm(() => {
|
|
6415
|
+
init_config();
|
|
6416
|
+
});
|
|
6417
|
+
|
|
6265
6418
|
// ../client/dist/index.js
|
|
6266
6419
|
var init_dist = __esm(() => {
|
|
6267
6420
|
init_build_env_prefixes();
|
|
@@ -6271,7 +6424,9 @@ var init_dist = __esm(() => {
|
|
|
6271
6424
|
init_errors();
|
|
6272
6425
|
init_apps();
|
|
6273
6426
|
init_auth();
|
|
6427
|
+
init_data();
|
|
6274
6428
|
init_logs();
|
|
6429
|
+
init_telemetry_consent();
|
|
6275
6430
|
});
|
|
6276
6431
|
|
|
6277
6432
|
// ../../node_modules/.bun/ignore@7.0.5/node_modules/ignore/index.js
|
|
@@ -6718,19 +6873,19 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
6718
6873
|
}
|
|
6719
6874
|
return t;
|
|
6720
6875
|
};
|
|
6721
|
-
__decorate = function(decorators,
|
|
6722
|
-
var c = arguments.length, r = c < 3 ?
|
|
6876
|
+
__decorate = function(decorators, target2, key, desc) {
|
|
6877
|
+
var c = arguments.length, r = c < 3 ? target2 : desc === null ? desc = Object.getOwnPropertyDescriptor(target2, key) : desc, d;
|
|
6723
6878
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
6724
|
-
r = Reflect.decorate(decorators,
|
|
6879
|
+
r = Reflect.decorate(decorators, target2, key, desc);
|
|
6725
6880
|
else
|
|
6726
6881
|
for (var i = decorators.length - 1;i >= 0; i--)
|
|
6727
6882
|
if (d = decorators[i])
|
|
6728
|
-
r = (c < 3 ? d(r) : c > 3 ? d(
|
|
6729
|
-
return c > 3 && r && Object.defineProperty(
|
|
6883
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target2, key, r) : d(target2, key)) || r;
|
|
6884
|
+
return c > 3 && r && Object.defineProperty(target2, key, r), r;
|
|
6730
6885
|
};
|
|
6731
6886
|
__param = function(paramIndex, decorator) {
|
|
6732
|
-
return function(
|
|
6733
|
-
decorator(
|
|
6887
|
+
return function(target2, key) {
|
|
6888
|
+
decorator(target2, key, paramIndex);
|
|
6734
6889
|
};
|
|
6735
6890
|
};
|
|
6736
6891
|
__esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
@@ -6740,8 +6895,8 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
6740
6895
|
return f;
|
|
6741
6896
|
}
|
|
6742
6897
|
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
6743
|
-
var
|
|
6744
|
-
var descriptor = descriptorIn || (
|
|
6898
|
+
var target2 = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
6899
|
+
var descriptor = descriptorIn || (target2 ? Object.getOwnPropertyDescriptor(target2, contextIn.name) : {});
|
|
6745
6900
|
var _, done = false;
|
|
6746
6901
|
for (var i = decorators.length - 1;i >= 0; i--) {
|
|
6747
6902
|
var context = {};
|
|
@@ -6773,8 +6928,8 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
6773
6928
|
descriptor[key] = _;
|
|
6774
6929
|
}
|
|
6775
6930
|
}
|
|
6776
|
-
if (
|
|
6777
|
-
Object.defineProperty(
|
|
6931
|
+
if (target2)
|
|
6932
|
+
Object.defineProperty(target2, contextIn.name, descriptor);
|
|
6778
6933
|
done = true;
|
|
6779
6934
|
};
|
|
6780
6935
|
__runInitializers = function(thisArg, initializers, value) {
|
|
@@ -8951,13 +9106,13 @@ var require_path_visitor = __commonJS((exports, module) => {
|
|
|
8951
9106
|
isFunction.assert(Visitor.visit);
|
|
8952
9107
|
return new Visitor;
|
|
8953
9108
|
};
|
|
8954
|
-
function extend2(
|
|
9109
|
+
function extend2(target2, source) {
|
|
8955
9110
|
for (var property in source) {
|
|
8956
9111
|
if (hasOwn.call(source, property)) {
|
|
8957
|
-
|
|
9112
|
+
target2[property] = source[property];
|
|
8958
9113
|
}
|
|
8959
9114
|
}
|
|
8960
|
-
return
|
|
9115
|
+
return target2;
|
|
8961
9116
|
}
|
|
8962
9117
|
PathVisitor.visit = function visit(node, methods) {
|
|
8963
9118
|
return PathVisitor.fromMethodsObject(methods).visit(node);
|
|
@@ -10582,7 +10737,7 @@ var require_util = __commonJS((exports) => {
|
|
|
10582
10737
|
return path;
|
|
10583
10738
|
}
|
|
10584
10739
|
exports.normalize = normalize2;
|
|
10585
|
-
function
|
|
10740
|
+
function join19(aRoot, aPath) {
|
|
10586
10741
|
if (aRoot === "") {
|
|
10587
10742
|
aRoot = ".";
|
|
10588
10743
|
}
|
|
@@ -10614,7 +10769,7 @@ var require_util = __commonJS((exports) => {
|
|
|
10614
10769
|
}
|
|
10615
10770
|
return joined;
|
|
10616
10771
|
}
|
|
10617
|
-
exports.join =
|
|
10772
|
+
exports.join = join19;
|
|
10618
10773
|
exports.isAbsolute = function(aPath) {
|
|
10619
10774
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
10620
10775
|
};
|
|
@@ -10787,7 +10942,7 @@ var require_util = __commonJS((exports) => {
|
|
|
10787
10942
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
10788
10943
|
}
|
|
10789
10944
|
}
|
|
10790
|
-
sourceURL =
|
|
10945
|
+
sourceURL = join19(urlGenerate(parsed), sourceURL);
|
|
10791
10946
|
}
|
|
10792
10947
|
return normalize2(sourceURL);
|
|
10793
10948
|
}
|
|
@@ -12532,27 +12687,27 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
12532
12687
|
};
|
|
12533
12688
|
CommentHandler2.prototype.findLeadingComments = function(metadata) {
|
|
12534
12689
|
var leadingComments = [];
|
|
12535
|
-
var
|
|
12690
|
+
var target2;
|
|
12536
12691
|
while (this.stack.length > 0) {
|
|
12537
12692
|
var entry = this.stack[this.stack.length - 1];
|
|
12538
12693
|
if (entry && entry.start >= metadata.start.offset) {
|
|
12539
|
-
|
|
12694
|
+
target2 = entry.node;
|
|
12540
12695
|
this.stack.pop();
|
|
12541
12696
|
} else {
|
|
12542
12697
|
break;
|
|
12543
12698
|
}
|
|
12544
12699
|
}
|
|
12545
|
-
if (
|
|
12546
|
-
var count =
|
|
12700
|
+
if (target2) {
|
|
12701
|
+
var count = target2.leadingComments ? target2.leadingComments.length : 0;
|
|
12547
12702
|
for (var i = count - 1;i >= 0; --i) {
|
|
12548
|
-
var comment =
|
|
12703
|
+
var comment = target2.leadingComments[i];
|
|
12549
12704
|
if (comment.range[1] <= metadata.start.offset) {
|
|
12550
12705
|
leadingComments.unshift(comment);
|
|
12551
|
-
|
|
12706
|
+
target2.leadingComments.splice(i, 1);
|
|
12552
12707
|
}
|
|
12553
12708
|
}
|
|
12554
|
-
if (
|
|
12555
|
-
delete
|
|
12709
|
+
if (target2.leadingComments && target2.leadingComments.length === 0) {
|
|
12710
|
+
delete target2.leadingComments;
|
|
12556
12711
|
}
|
|
12557
12712
|
return leadingComments;
|
|
12558
12713
|
}
|
|
@@ -13038,9 +13193,9 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13038
13193
|
if (this.match("}")) {
|
|
13039
13194
|
this.tolerateError("JSX attributes must only be assigned a non-empty expression");
|
|
13040
13195
|
}
|
|
13041
|
-
var
|
|
13196
|
+
var expression2 = this.parseAssignmentExpression();
|
|
13042
13197
|
this.reenterJSX();
|
|
13043
|
-
return this.finalize(node, new JSXNode.JSXExpressionContainer(
|
|
13198
|
+
return this.finalize(node, new JSXNode.JSXExpressionContainer(expression2));
|
|
13044
13199
|
};
|
|
13045
13200
|
JSXParser2.prototype.parseJSXAttributeValue = function() {
|
|
13046
13201
|
return this.matchJSX("{") ? this.parseJSXExpressionAttribute() : this.matchJSX("<") ? this.parseJSXElement() : this.parseJSXStringLiteralAttribute();
|
|
@@ -13113,16 +13268,16 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13113
13268
|
JSXParser2.prototype.parseJSXExpressionContainer = function() {
|
|
13114
13269
|
var node = this.createJSXNode();
|
|
13115
13270
|
this.expectJSX("{");
|
|
13116
|
-
var
|
|
13271
|
+
var expression2;
|
|
13117
13272
|
if (this.matchJSX("}")) {
|
|
13118
|
-
|
|
13273
|
+
expression2 = this.parseJSXEmptyExpression();
|
|
13119
13274
|
this.expectJSX("}");
|
|
13120
13275
|
} else {
|
|
13121
13276
|
this.finishJSX();
|
|
13122
|
-
|
|
13277
|
+
expression2 = this.parseAssignmentExpression();
|
|
13123
13278
|
this.reenterJSX();
|
|
13124
13279
|
}
|
|
13125
|
-
return this.finalize(node, new JSXNode.JSXExpressionContainer(
|
|
13280
|
+
return this.finalize(node, new JSXNode.JSXExpressionContainer(expression2));
|
|
13126
13281
|
};
|
|
13127
13282
|
JSXParser2.prototype.parseJSXChildren = function() {
|
|
13128
13283
|
var children = [];
|
|
@@ -13268,9 +13423,9 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13268
13423
|
}();
|
|
13269
13424
|
exports2.JSXEmptyExpression = JSXEmptyExpression;
|
|
13270
13425
|
var JSXExpressionContainer = function() {
|
|
13271
|
-
function JSXExpressionContainer2(
|
|
13426
|
+
function JSXExpressionContainer2(expression2) {
|
|
13272
13427
|
this.type = jsx_syntax_1.JSXSyntax.JSXExpressionContainer;
|
|
13273
|
-
this.expression =
|
|
13428
|
+
this.expression = expression2;
|
|
13274
13429
|
}
|
|
13275
13430
|
return JSXExpressionContainer2;
|
|
13276
13431
|
}();
|
|
@@ -13374,13 +13529,13 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13374
13529
|
}();
|
|
13375
13530
|
exports2.ArrayPattern = ArrayPattern;
|
|
13376
13531
|
var ArrowFunctionExpression = function() {
|
|
13377
|
-
function ArrowFunctionExpression2(params, body,
|
|
13532
|
+
function ArrowFunctionExpression2(params, body, expression2) {
|
|
13378
13533
|
this.type = syntax_1.Syntax.ArrowFunctionExpression;
|
|
13379
13534
|
this.id = null;
|
|
13380
13535
|
this.params = params;
|
|
13381
13536
|
this.body = body;
|
|
13382
13537
|
this.generator = false;
|
|
13383
|
-
this.expression =
|
|
13538
|
+
this.expression = expression2;
|
|
13384
13539
|
this.async = false;
|
|
13385
13540
|
}
|
|
13386
13541
|
return ArrowFunctionExpression2;
|
|
@@ -13406,13 +13561,13 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13406
13561
|
}();
|
|
13407
13562
|
exports2.AssignmentPattern = AssignmentPattern;
|
|
13408
13563
|
var AsyncArrowFunctionExpression = function() {
|
|
13409
|
-
function AsyncArrowFunctionExpression2(params, body,
|
|
13564
|
+
function AsyncArrowFunctionExpression2(params, body, expression2) {
|
|
13410
13565
|
this.type = syntax_1.Syntax.ArrowFunctionExpression;
|
|
13411
13566
|
this.id = null;
|
|
13412
13567
|
this.params = params;
|
|
13413
13568
|
this.body = body;
|
|
13414
13569
|
this.generator = false;
|
|
13415
|
-
this.expression =
|
|
13570
|
+
this.expression = expression2;
|
|
13416
13571
|
this.async = true;
|
|
13417
13572
|
}
|
|
13418
13573
|
return AsyncArrowFunctionExpression2;
|
|
@@ -13561,9 +13716,9 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13561
13716
|
}();
|
|
13562
13717
|
exports2.DebuggerStatement = DebuggerStatement;
|
|
13563
13718
|
var Directive = function() {
|
|
13564
|
-
function Directive2(
|
|
13719
|
+
function Directive2(expression2, directive) {
|
|
13565
13720
|
this.type = syntax_1.Syntax.ExpressionStatement;
|
|
13566
|
-
this.expression =
|
|
13721
|
+
this.expression = expression2;
|
|
13567
13722
|
this.directive = directive;
|
|
13568
13723
|
}
|
|
13569
13724
|
return Directive2;
|
|
@@ -13621,9 +13776,9 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
13621
13776
|
}();
|
|
13622
13777
|
exports2.ExportSpecifier = ExportSpecifier;
|
|
13623
13778
|
var ExpressionStatement = function() {
|
|
13624
|
-
function ExpressionStatement2(
|
|
13779
|
+
function ExpressionStatement2(expression2) {
|
|
13625
13780
|
this.type = syntax_1.Syntax.ExpressionStatement;
|
|
13626
|
-
this.expression =
|
|
13781
|
+
this.expression = expression2;
|
|
13627
13782
|
}
|
|
13628
13783
|
return ExpressionStatement2;
|
|
13629
13784
|
}();
|
|
@@ -15357,14 +15512,14 @@ var require_esprima2 = __commonJS((exports, module) => {
|
|
|
15357
15512
|
} else {
|
|
15358
15513
|
body = this.isolateCoverGrammar(this.parseAssignmentExpression);
|
|
15359
15514
|
}
|
|
15360
|
-
var
|
|
15515
|
+
var expression2 = body.type !== syntax_1.Syntax.BlockStatement;
|
|
15361
15516
|
if (this.context.strict && list.firstRestricted) {
|
|
15362
15517
|
this.throwUnexpectedToken(list.firstRestricted, list.message);
|
|
15363
15518
|
}
|
|
15364
15519
|
if (this.context.strict && list.stricted) {
|
|
15365
15520
|
this.tolerateUnexpectedToken(list.stricted, list.message);
|
|
15366
15521
|
}
|
|
15367
|
-
expr = isAsync ? this.finalize(node, new Node.AsyncArrowFunctionExpression(list.params, body,
|
|
15522
|
+
expr = isAsync ? this.finalize(node, new Node.AsyncArrowFunctionExpression(list.params, body, expression2)) : this.finalize(node, new Node.ArrowFunctionExpression(list.params, body, expression2));
|
|
15368
15523
|
this.context.strict = previousStrict;
|
|
15369
15524
|
this.context.allowStrictDirective = previousAllowStrictDirective;
|
|
15370
15525
|
this.context.allowYield = previousAllowYield;
|
|
@@ -19914,7 +20069,7 @@ var require_fast_path = __commonJS((exports) => {
|
|
|
19914
20069
|
}
|
|
19915
20070
|
return s[0];
|
|
19916
20071
|
};
|
|
19917
|
-
FPp.call = function
|
|
20072
|
+
FPp.call = function call2(callback) {
|
|
19918
20073
|
var s = this.stack;
|
|
19919
20074
|
var origLen = s.length;
|
|
19920
20075
|
var value = s[origLen - 1];
|
|
@@ -22157,8 +22312,8 @@ while`);
|
|
|
22157
22312
|
return (0, lines_1.concat)([path.call(print, "left"), ".", path.call(print, "right")]);
|
|
22158
22313
|
case "TSAsExpression":
|
|
22159
22314
|
case "TSSatisfiesExpression": {
|
|
22160
|
-
var
|
|
22161
|
-
parts.push(
|
|
22315
|
+
var expression2 = path.call(print, "expression");
|
|
22316
|
+
parts.push(expression2, n.type === "TSSatisfiesExpression" ? " satisfies " : " as ", path.call(print, "typeAnnotation"));
|
|
22162
22317
|
return (0, lines_1.concat)(parts);
|
|
22163
22318
|
}
|
|
22164
22319
|
case "TSTypeCastExpression":
|
|
@@ -23793,9 +23948,9 @@ var require_lib = __commonJS((exports) => {
|
|
|
23793
23948
|
UnsupportedDefaultExport: "Only expressions, functions or classes are allowed as the `default` export.",
|
|
23794
23949
|
UnsupportedImport: "`import` can only be used in `import()` or `import.meta`.",
|
|
23795
23950
|
UnsupportedMetaProperty: ({
|
|
23796
|
-
target,
|
|
23951
|
+
target: target2,
|
|
23797
23952
|
onlyValidPropertyName
|
|
23798
|
-
}) => `The only valid meta property for ${
|
|
23953
|
+
}) => `The only valid meta property for ${target2} is ${target2}.${onlyValidPropertyName}.`,
|
|
23799
23954
|
UnsupportedParameterDecorator: "Decorators cannot be used to decorate parameters.",
|
|
23800
23955
|
UnsupportedPropertyDecorator: "Decorators cannot be used to decorate object literal properties.",
|
|
23801
23956
|
UnsupportedSuper: "'super' can only be used with function calls (i.e. super()) or in property accesses (i.e. super.prop or super[prop]).",
|
|
@@ -24083,15 +24238,15 @@ var require_lib = __commonJS((exports) => {
|
|
|
24083
24238
|
return this.finishNodeAt(chain, "ChainExpression", endLoc);
|
|
24084
24239
|
}
|
|
24085
24240
|
directiveToStmt(directive) {
|
|
24086
|
-
const
|
|
24241
|
+
const expression2 = directive.value;
|
|
24087
24242
|
delete directive.value;
|
|
24088
|
-
this.castNodeTo(
|
|
24089
|
-
|
|
24090
|
-
|
|
24243
|
+
this.castNodeTo(expression2, "Literal");
|
|
24244
|
+
expression2.raw = expression2.extra.raw;
|
|
24245
|
+
expression2.value = expression2.extra.expressionValue;
|
|
24091
24246
|
const stmt = this.castNodeTo(directive, "ExpressionStatement");
|
|
24092
|
-
stmt.expression =
|
|
24093
|
-
stmt.directive =
|
|
24094
|
-
delete
|
|
24247
|
+
stmt.expression = expression2;
|
|
24248
|
+
stmt.directive = expression2.extra.rawValue;
|
|
24249
|
+
delete expression2.extra;
|
|
24095
24250
|
return stmt;
|
|
24096
24251
|
}
|
|
24097
24252
|
fillOptionalPropertiesForTSESLint(node) {}
|
|
@@ -27042,14 +27197,14 @@ var require_lib = __commonJS((exports) => {
|
|
|
27042
27197
|
this.resetEndLocation(decl.id);
|
|
27043
27198
|
}
|
|
27044
27199
|
}
|
|
27045
|
-
parseAsyncArrowFromCallExpression(node,
|
|
27200
|
+
parseAsyncArrowFromCallExpression(node, call2) {
|
|
27046
27201
|
if (this.match(14)) {
|
|
27047
27202
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
|
27048
27203
|
this.state.noAnonFunctionType = true;
|
|
27049
27204
|
node.returnType = this.flowParseTypeAnnotation();
|
|
27050
27205
|
this.state.noAnonFunctionType = oldNoAnonFunctionType;
|
|
27051
27206
|
}
|
|
27052
|
-
return super.parseAsyncArrowFromCallExpression(node,
|
|
27207
|
+
return super.parseAsyncArrowFromCallExpression(node, call2);
|
|
27053
27208
|
}
|
|
27054
27209
|
shouldParseAsyncArrow() {
|
|
27055
27210
|
return this.match(14) || super.shouldParseAsyncArrow();
|
|
@@ -28203,8 +28358,8 @@ var require_lib = __commonJS((exports) => {
|
|
|
28203
28358
|
if (this.match(8)) {
|
|
28204
28359
|
node.expression = this.jsxParseEmptyExpression();
|
|
28205
28360
|
} else {
|
|
28206
|
-
const
|
|
28207
|
-
node.expression =
|
|
28361
|
+
const expression2 = this.parseExpression();
|
|
28362
|
+
node.expression = expression2;
|
|
28208
28363
|
}
|
|
28209
28364
|
this.setContext(previousContext);
|
|
28210
28365
|
this.state.canStartJSXElement = true;
|
|
@@ -31140,53 +31295,53 @@ var require_lib = __commonJS((exports) => {
|
|
|
31140
31295
|
}
|
|
31141
31296
|
return false;
|
|
31142
31297
|
}
|
|
31143
|
-
isOptionalMemberExpression(
|
|
31144
|
-
return
|
|
31298
|
+
isOptionalMemberExpression(expression2) {
|
|
31299
|
+
return expression2.type === "OptionalMemberExpression";
|
|
31145
31300
|
}
|
|
31146
|
-
checkLVal(
|
|
31301
|
+
checkLVal(expression2, ancestor, binding = 64, checkClashes = false, strictModeChanged = false, hasParenthesizedAncestor = false, disallowCallExpression = false) {
|
|
31147
31302
|
var _expression$extra;
|
|
31148
|
-
const type =
|
|
31149
|
-
if (this.isObjectMethod(
|
|
31303
|
+
const type = expression2.type;
|
|
31304
|
+
if (this.isObjectMethod(expression2))
|
|
31150
31305
|
return;
|
|
31151
|
-
const isOptionalMemberExpression = this.isOptionalMemberExpression(
|
|
31306
|
+
const isOptionalMemberExpression = this.isOptionalMemberExpression(expression2);
|
|
31152
31307
|
if (isOptionalMemberExpression || type === "MemberExpression") {
|
|
31153
31308
|
if (isOptionalMemberExpression) {
|
|
31154
|
-
this.expectPlugin("optionalChainingAssign",
|
|
31309
|
+
this.expectPlugin("optionalChainingAssign", expression2.loc.start);
|
|
31155
31310
|
if (ancestor.type !== "AssignmentExpression") {
|
|
31156
|
-
this.raise(Errors.InvalidLhsOptionalChaining,
|
|
31311
|
+
this.raise(Errors.InvalidLhsOptionalChaining, expression2, {
|
|
31157
31312
|
ancestor
|
|
31158
31313
|
});
|
|
31159
31314
|
}
|
|
31160
31315
|
}
|
|
31161
31316
|
if (binding !== 64) {
|
|
31162
|
-
this.raise(Errors.InvalidPropertyBindingPattern,
|
|
31317
|
+
this.raise(Errors.InvalidPropertyBindingPattern, expression2);
|
|
31163
31318
|
}
|
|
31164
31319
|
return;
|
|
31165
31320
|
}
|
|
31166
31321
|
if (type === "Identifier") {
|
|
31167
|
-
this.checkIdentifier(
|
|
31322
|
+
this.checkIdentifier(expression2, binding, strictModeChanged);
|
|
31168
31323
|
const {
|
|
31169
31324
|
name
|
|
31170
|
-
} =
|
|
31325
|
+
} = expression2;
|
|
31171
31326
|
if (checkClashes) {
|
|
31172
31327
|
if (checkClashes.has(name)) {
|
|
31173
|
-
this.raise(Errors.ParamDupe,
|
|
31328
|
+
this.raise(Errors.ParamDupe, expression2);
|
|
31174
31329
|
} else {
|
|
31175
31330
|
checkClashes.add(name);
|
|
31176
31331
|
}
|
|
31177
31332
|
}
|
|
31178
31333
|
return;
|
|
31179
31334
|
} else if (type === "VoidPattern" && ancestor.type === "CatchClause") {
|
|
31180
|
-
this.raise(Errors.VoidPatternCatchClauseParam,
|
|
31335
|
+
this.raise(Errors.VoidPatternCatchClauseParam, expression2);
|
|
31181
31336
|
}
|
|
31182
|
-
const unwrappedExpression = unwrapParenthesizedExpression(
|
|
31337
|
+
const unwrappedExpression = unwrapParenthesizedExpression(expression2);
|
|
31183
31338
|
disallowCallExpression || (disallowCallExpression = unwrappedExpression.type === "CallExpression" && (unwrappedExpression.callee.type === "Import" || unwrappedExpression.callee.type === "Super"));
|
|
31184
|
-
const validity = this.isValidLVal(type, disallowCallExpression, !(hasParenthesizedAncestor || (_expression$extra =
|
|
31339
|
+
const validity = this.isValidLVal(type, disallowCallExpression, !(hasParenthesizedAncestor || (_expression$extra = expression2.extra) != null && _expression$extra.parenthesized) && ancestor.type === "AssignmentExpression", binding);
|
|
31185
31340
|
if (validity === true)
|
|
31186
31341
|
return;
|
|
31187
31342
|
if (validity === false) {
|
|
31188
31343
|
const ParseErrorClass = binding === 64 ? Errors.InvalidLhs : Errors.InvalidLhsBinding;
|
|
31189
|
-
this.raise(ParseErrorClass,
|
|
31344
|
+
this.raise(ParseErrorClass, expression2, {
|
|
31190
31345
|
ancestor
|
|
31191
31346
|
});
|
|
31192
31347
|
return;
|
|
@@ -31201,7 +31356,7 @@ var require_lib = __commonJS((exports) => {
|
|
|
31201
31356
|
const nextAncestor = type === "ArrayPattern" || type === "ObjectPattern" ? {
|
|
31202
31357
|
type
|
|
31203
31358
|
} : ancestor;
|
|
31204
|
-
const val =
|
|
31359
|
+
const val = expression2[key];
|
|
31205
31360
|
if (Array.isArray(val)) {
|
|
31206
31361
|
for (const child of val) {
|
|
31207
31362
|
if (child) {
|
|
@@ -33459,11 +33614,11 @@ var require_lib = __commonJS((exports) => {
|
|
|
33459
33614
|
this.resetEndLocation(decl.id);
|
|
33460
33615
|
}
|
|
33461
33616
|
}
|
|
33462
|
-
parseAsyncArrowFromCallExpression(node,
|
|
33617
|
+
parseAsyncArrowFromCallExpression(node, call2) {
|
|
33463
33618
|
if (this.match(14)) {
|
|
33464
33619
|
node.returnType = this.tsParseTypeAnnotation();
|
|
33465
33620
|
}
|
|
33466
|
-
return super.parseAsyncArrowFromCallExpression(node,
|
|
33621
|
+
return super.parseAsyncArrowFromCallExpression(node, call2);
|
|
33467
33622
|
}
|
|
33468
33623
|
parseMaybeAssign(refExpressionErrors, afterLeftParse) {
|
|
33469
33624
|
var _jsx, _jsx2, _typeCast, _jsx3, _typeCast2;
|
|
@@ -33654,9 +33809,9 @@ var require_lib = __commonJS((exports) => {
|
|
|
33654
33809
|
if (this.match(47) || this.match(51)) {
|
|
33655
33810
|
const typeArguments = this.tsParseTypeArgumentsInExpression();
|
|
33656
33811
|
if (this.match(10)) {
|
|
33657
|
-
const
|
|
33658
|
-
|
|
33659
|
-
return
|
|
33812
|
+
const call2 = super.parseMaybeDecoratorArguments(expr, startLoc);
|
|
33813
|
+
call2.typeParameters = typeArguments;
|
|
33814
|
+
return call2;
|
|
33660
33815
|
}
|
|
33661
33816
|
this.unexpected(null, 10);
|
|
33662
33817
|
}
|
|
@@ -34046,31 +34201,31 @@ var require_lib = __commonJS((exports) => {
|
|
|
34046
34201
|
return this.chStartsBindingIdentifier(nextCh, next) || nextCh === 34 || nextCh === 39;
|
|
34047
34202
|
}
|
|
34048
34203
|
};
|
|
34049
|
-
function isPossiblyLiteralEnum(
|
|
34050
|
-
if (
|
|
34204
|
+
function isPossiblyLiteralEnum(expression2) {
|
|
34205
|
+
if (expression2.type !== "MemberExpression")
|
|
34051
34206
|
return false;
|
|
34052
34207
|
const {
|
|
34053
34208
|
computed,
|
|
34054
34209
|
property
|
|
34055
|
-
} =
|
|
34210
|
+
} = expression2;
|
|
34056
34211
|
if (computed && property.type !== "StringLiteral" && (property.type !== "TemplateLiteral" || property.expressions.length > 0)) {
|
|
34057
34212
|
return false;
|
|
34058
34213
|
}
|
|
34059
|
-
return isUncomputedMemberExpressionChain(
|
|
34214
|
+
return isUncomputedMemberExpressionChain(expression2.object);
|
|
34060
34215
|
}
|
|
34061
|
-
function isValidAmbientConstInitializer(
|
|
34216
|
+
function isValidAmbientConstInitializer(expression2, estree2) {
|
|
34062
34217
|
var _expression$extra;
|
|
34063
34218
|
const {
|
|
34064
34219
|
type
|
|
34065
|
-
} =
|
|
34066
|
-
if ((_expression$extra =
|
|
34220
|
+
} = expression2;
|
|
34221
|
+
if ((_expression$extra = expression2.extra) != null && _expression$extra.parenthesized) {
|
|
34067
34222
|
return false;
|
|
34068
34223
|
}
|
|
34069
34224
|
if (estree2) {
|
|
34070
34225
|
if (type === "Literal") {
|
|
34071
34226
|
const {
|
|
34072
34227
|
value
|
|
34073
|
-
} =
|
|
34228
|
+
} = expression2;
|
|
34074
34229
|
if (typeof value === "string" || typeof value === "boolean") {
|
|
34075
34230
|
return true;
|
|
34076
34231
|
}
|
|
@@ -34080,42 +34235,42 @@ var require_lib = __commonJS((exports) => {
|
|
|
34080
34235
|
return true;
|
|
34081
34236
|
}
|
|
34082
34237
|
}
|
|
34083
|
-
if (isNumber(
|
|
34238
|
+
if (isNumber(expression2, estree2) || isNegativeNumber(expression2, estree2)) {
|
|
34084
34239
|
return true;
|
|
34085
34240
|
}
|
|
34086
|
-
if (type === "TemplateLiteral" &&
|
|
34241
|
+
if (type === "TemplateLiteral" && expression2.expressions.length === 0) {
|
|
34087
34242
|
return true;
|
|
34088
34243
|
}
|
|
34089
|
-
if (isPossiblyLiteralEnum(
|
|
34244
|
+
if (isPossiblyLiteralEnum(expression2)) {
|
|
34090
34245
|
return true;
|
|
34091
34246
|
}
|
|
34092
34247
|
return false;
|
|
34093
34248
|
}
|
|
34094
|
-
function isNumber(
|
|
34249
|
+
function isNumber(expression2, estree2) {
|
|
34095
34250
|
if (estree2) {
|
|
34096
|
-
return
|
|
34251
|
+
return expression2.type === "Literal" && (typeof expression2.value === "number" || ("bigint" in expression2));
|
|
34097
34252
|
}
|
|
34098
|
-
return
|
|
34253
|
+
return expression2.type === "NumericLiteral" || expression2.type === "BigIntLiteral";
|
|
34099
34254
|
}
|
|
34100
|
-
function isNegativeNumber(
|
|
34101
|
-
if (
|
|
34255
|
+
function isNegativeNumber(expression2, estree2) {
|
|
34256
|
+
if (expression2.type === "UnaryExpression") {
|
|
34102
34257
|
const {
|
|
34103
34258
|
operator,
|
|
34104
34259
|
argument
|
|
34105
|
-
} =
|
|
34260
|
+
} = expression2;
|
|
34106
34261
|
if (operator === "-" && isNumber(argument, estree2)) {
|
|
34107
34262
|
return true;
|
|
34108
34263
|
}
|
|
34109
34264
|
}
|
|
34110
34265
|
return false;
|
|
34111
34266
|
}
|
|
34112
|
-
function isUncomputedMemberExpressionChain(
|
|
34113
|
-
if (
|
|
34267
|
+
function isUncomputedMemberExpressionChain(expression2) {
|
|
34268
|
+
if (expression2.type === "Identifier")
|
|
34114
34269
|
return true;
|
|
34115
|
-
if (
|
|
34270
|
+
if (expression2.type !== "MemberExpression" || expression2.computed) {
|
|
34116
34271
|
return false;
|
|
34117
34272
|
}
|
|
34118
|
-
return isUncomputedMemberExpressionChain(
|
|
34273
|
+
return isUncomputedMemberExpressionChain(expression2.object);
|
|
34119
34274
|
}
|
|
34120
34275
|
var PlaceholderErrors = ParseErrorEnum`placeholders`({
|
|
34121
34276
|
ClassNameIsRequired: "A class name is required.",
|
|
@@ -34977,16 +35132,16 @@ var require_lib = __commonJS((exports) => {
|
|
|
34977
35132
|
shouldParseAsyncArrow() {
|
|
34978
35133
|
return this.match(19) && !this.canInsertSemicolon();
|
|
34979
35134
|
}
|
|
34980
|
-
parseAsyncArrowFromCallExpression(node,
|
|
35135
|
+
parseAsyncArrowFromCallExpression(node, call2) {
|
|
34981
35136
|
var _call$extra;
|
|
34982
|
-
this.resetPreviousNodeTrailingComments(
|
|
35137
|
+
this.resetPreviousNodeTrailingComments(call2);
|
|
34983
35138
|
this.expect(19);
|
|
34984
|
-
this.parseArrowExpression(node,
|
|
34985
|
-
if (
|
|
34986
|
-
setInnerComments(node,
|
|
35139
|
+
this.parseArrowExpression(node, call2.arguments, true, (_call$extra = call2.extra) == null ? undefined : _call$extra.trailingCommaLoc);
|
|
35140
|
+
if (call2.innerComments) {
|
|
35141
|
+
setInnerComments(node, call2.innerComments);
|
|
34987
35142
|
}
|
|
34988
|
-
if (
|
|
34989
|
-
setInnerComments(node,
|
|
35143
|
+
if (call2.callee.trailingComments) {
|
|
35144
|
+
setInnerComments(node, call2.callee.trailingComments);
|
|
34990
35145
|
}
|
|
34991
35146
|
return node;
|
|
34992
35147
|
}
|
|
@@ -35414,15 +35569,15 @@ var require_lib = __commonJS((exports) => {
|
|
|
35414
35569
|
}
|
|
35415
35570
|
return this.wrapParenthesis(startLoc, val);
|
|
35416
35571
|
}
|
|
35417
|
-
wrapParenthesis(startLoc,
|
|
35572
|
+
wrapParenthesis(startLoc, expression2) {
|
|
35418
35573
|
if (!(this.optionFlags & 1024)) {
|
|
35419
|
-
this.addExtra(
|
|
35420
|
-
this.addExtra(
|
|
35421
|
-
this.takeSurroundingComments(
|
|
35422
|
-
return
|
|
35574
|
+
this.addExtra(expression2, "parenthesized", true);
|
|
35575
|
+
this.addExtra(expression2, "parenStart", startLoc.index);
|
|
35576
|
+
this.takeSurroundingComments(expression2, startLoc.index, this.state.lastTokEndLoc.index);
|
|
35577
|
+
return expression2;
|
|
35423
35578
|
}
|
|
35424
35579
|
const parenExpression = this.startNodeAt(startLoc);
|
|
35425
|
-
parenExpression.expression =
|
|
35580
|
+
parenExpression.expression = expression2;
|
|
35426
35581
|
return this.finishNode(parenExpression, "ParenthesizedExpression");
|
|
35427
35582
|
}
|
|
35428
35583
|
shouldParseArrow(params) {
|
|
@@ -36070,10 +36225,10 @@ var require_lib = __commonJS((exports) => {
|
|
|
36070
36225
|
return this.finishNode(bodyNode, "PipelineTopicExpression");
|
|
36071
36226
|
}
|
|
36072
36227
|
}
|
|
36073
|
-
isSimpleReference(
|
|
36074
|
-
switch (
|
|
36228
|
+
isSimpleReference(expression2) {
|
|
36229
|
+
switch (expression2.type) {
|
|
36075
36230
|
case "MemberExpression":
|
|
36076
|
-
return !
|
|
36231
|
+
return !expression2.computed && this.isSimpleReference(expression2.object);
|
|
36077
36232
|
case "Identifier":
|
|
36078
36233
|
return true;
|
|
36079
36234
|
default:
|
|
@@ -86844,17 +86999,17 @@ var require_template = __commonJS((exports, module) => {
|
|
|
86844
86999
|
function statement() {
|
|
86845
87000
|
return statements.apply(null, arguments)[0];
|
|
86846
87001
|
}
|
|
86847
|
-
function
|
|
87002
|
+
function expression2(template) {
|
|
86848
87003
|
template = Array.from(template);
|
|
86849
87004
|
if (template.length > 0) {
|
|
86850
87005
|
template[0] = "(" + template[0];
|
|
86851
87006
|
template[template.length - 1] += ")";
|
|
86852
87007
|
}
|
|
86853
|
-
const
|
|
86854
|
-
if (
|
|
86855
|
-
|
|
87008
|
+
const expression3 = statement.apply(null, [template].concat(Array.from(arguments).slice(1))).expression;
|
|
87009
|
+
if (expression3.extra) {
|
|
87010
|
+
expression3.extra.parenthesized = false;
|
|
86856
87011
|
}
|
|
86857
|
-
return
|
|
87012
|
+
return expression3;
|
|
86858
87013
|
}
|
|
86859
87014
|
function asyncExpression(template) {
|
|
86860
87015
|
template = Array.from(template);
|
|
@@ -86862,13 +87017,13 @@ var require_template = __commonJS((exports, module) => {
|
|
|
86862
87017
|
template[0] = "async () => (" + template[0];
|
|
86863
87018
|
template[template.length - 1] += ")";
|
|
86864
87019
|
}
|
|
86865
|
-
const
|
|
86866
|
-
if (
|
|
86867
|
-
|
|
87020
|
+
const expression3 = statement.apply(null, [template].concat(Array.from(arguments).slice(1))).expression.body;
|
|
87021
|
+
if (expression3.extra) {
|
|
87022
|
+
expression3.extra.parenthesized = false;
|
|
86868
87023
|
}
|
|
86869
|
-
return
|
|
87024
|
+
return expression3;
|
|
86870
87025
|
}
|
|
86871
|
-
return { statements, statement, expression, asyncExpression };
|
|
87026
|
+
return { statements, statement, expression: expression2, asyncExpression };
|
|
86872
87027
|
};
|
|
86873
87028
|
});
|
|
86874
87029
|
|
|
@@ -92665,15 +92820,161 @@ function iconColourHex(token) {
|
|
|
92665
92820
|
return BRAND.green;
|
|
92666
92821
|
return ICON_COLOURS[token] ?? BRAND.green;
|
|
92667
92822
|
}
|
|
92823
|
+
// ../shared/dist/data-records.js
|
|
92824
|
+
var DATA_COLLECTION_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
|
|
92825
|
+
var DATA_RECORD_ID_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
92826
|
+
var DATA_LIMITS = {
|
|
92827
|
+
bodyBytes: 262144,
|
|
92828
|
+
responseBytes: 1048576,
|
|
92829
|
+
maxPage: 1000,
|
|
92830
|
+
maxPerPage: 100,
|
|
92831
|
+
expressionChars: 1024,
|
|
92832
|
+
filterMaxDepth: 16,
|
|
92833
|
+
filterMaxComparisons: 64,
|
|
92834
|
+
accessMaxApps: 50,
|
|
92835
|
+
schemaPerPage: 200,
|
|
92836
|
+
schemaMaxPages: 10,
|
|
92837
|
+
sortMaxItems: 8,
|
|
92838
|
+
actAsTokenSeconds: 900,
|
|
92839
|
+
actAsCacheMaxSeconds: 600,
|
|
92840
|
+
identityCandidatesPerPage: 20
|
|
92841
|
+
};
|
|
92842
|
+
var DATA_IDENTITY_KINDS = ["user", "visitor", "superuser"];
|
|
92843
|
+
var DATA_ACTING_AS = [...DATA_IDENTITY_KINDS, "unset"];
|
|
92844
|
+
var DATA_RECORD_ERROR_STATUS = {
|
|
92845
|
+
PB_VERSION_UNSUPPORTED: 503,
|
|
92846
|
+
PB_RECORD_NOT_FOUND: 404,
|
|
92847
|
+
PB_VALIDATION: 400,
|
|
92848
|
+
PB_CONFLICT: 409,
|
|
92849
|
+
PB_CONFLICT_UNSUPPORTED: 400,
|
|
92850
|
+
DATA_COLLECTION_FORBIDDEN: 403,
|
|
92851
|
+
DATA_FIELD_UNSUPPORTED: 400,
|
|
92852
|
+
DATA_RATE_LIMITED: 429,
|
|
92853
|
+
DATA_RESPONSE_TOO_LARGE: 413,
|
|
92854
|
+
OAUTH_DATA_ACCESS_REQUIRED: 403,
|
|
92855
|
+
DATA_TOOLS_NOT_ENABLED: 403,
|
|
92856
|
+
PB_AUTH_FAILED: 503,
|
|
92857
|
+
PB_NOT_RUNNING: 503,
|
|
92858
|
+
PB_BRIDGE_UNAVAILABLE: 502,
|
|
92859
|
+
NOT_POCKETBASE: 400,
|
|
92860
|
+
DATA_QUERY_INVALID: 400,
|
|
92861
|
+
DATA_SCHEMA_TOO_LARGE: 413,
|
|
92862
|
+
DATA_QUERY_TIMEOUT: 504,
|
|
92863
|
+
DATA_WRITE_OUTCOME_UNKNOWN: 502,
|
|
92864
|
+
PB_RULE_DENIED: 403,
|
|
92865
|
+
DATA_ACT_AS_REQUIRED: 403,
|
|
92866
|
+
DATA_ACT_AS_UNAVAILABLE: 403
|
|
92867
|
+
};
|
|
92868
|
+
|
|
92869
|
+
// ../shared/dist/data-filter.js
|
|
92870
|
+
class ExpressionError extends Error {
|
|
92871
|
+
reason;
|
|
92872
|
+
at;
|
|
92873
|
+
constructor(reason, at) {
|
|
92874
|
+
super(reason);
|
|
92875
|
+
this.reason = reason;
|
|
92876
|
+
this.at = at;
|
|
92877
|
+
}
|
|
92878
|
+
}
|
|
92879
|
+
var RESERVED = new Set(["true", "false", "null"]);
|
|
92880
|
+
class SchemaIndex {
|
|
92881
|
+
visible = new Set;
|
|
92882
|
+
hidden = new Set;
|
|
92883
|
+
lowered = new Set;
|
|
92884
|
+
constructor(fields) {
|
|
92885
|
+
for (const f of fields) {
|
|
92886
|
+
(f.hidden ? this.hidden : this.visible).add(f.name);
|
|
92887
|
+
this.lowered.add(f.name.toLowerCase());
|
|
92888
|
+
}
|
|
92889
|
+
}
|
|
92890
|
+
checkField(name, at) {
|
|
92891
|
+
if (RESERVED.has(name.toLowerCase()))
|
|
92892
|
+
throw new ExpressionError("reserved_word", at);
|
|
92893
|
+
if (this.visible.has(name))
|
|
92894
|
+
return;
|
|
92895
|
+
throw new ExpressionError(this.hidden.has(name) ? "hidden_field" : "unknown_field", at);
|
|
92896
|
+
}
|
|
92897
|
+
checkKeywordLiteral(word, at) {
|
|
92898
|
+
if (this.lowered.has(word))
|
|
92899
|
+
throw new ExpressionError("shadowed_literal", at);
|
|
92900
|
+
}
|
|
92901
|
+
}
|
|
92902
|
+
// ../shared/dist/disposable-email-domains.js
|
|
92903
|
+
var DISPOSABLE_DOMAINS = new Set([
|
|
92904
|
+
"mailinator.com",
|
|
92905
|
+
"mailinator.net",
|
|
92906
|
+
"mailinator2.com",
|
|
92907
|
+
"binkmail.com",
|
|
92908
|
+
"bobmail.info",
|
|
92909
|
+
"chammy.info",
|
|
92910
|
+
"devnullmail.com",
|
|
92911
|
+
"letthemeatspam.com",
|
|
92912
|
+
"mailnesia.com",
|
|
92913
|
+
"mailtothis.com",
|
|
92914
|
+
"notmailinator.com",
|
|
92915
|
+
"reallymymail.com",
|
|
92916
|
+
"safetymail.info",
|
|
92917
|
+
"thisisnotmyrealemail.com",
|
|
92918
|
+
"tradermail.info",
|
|
92919
|
+
"veryrealemail.com",
|
|
92920
|
+
"zippymail.info",
|
|
92921
|
+
"guerrillamail.com",
|
|
92922
|
+
"guerrillamail.net",
|
|
92923
|
+
"guerrillamail.org",
|
|
92924
|
+
"guerrillamail.biz",
|
|
92925
|
+
"guerrillamail.de",
|
|
92926
|
+
"guerrillamailblock.com",
|
|
92927
|
+
"sharklasers.com",
|
|
92928
|
+
"grr.la",
|
|
92929
|
+
"spam4.me",
|
|
92930
|
+
"10minutemail.com",
|
|
92931
|
+
"10minutemail.net",
|
|
92932
|
+
"20minutemail.com",
|
|
92933
|
+
"30minutemail.com",
|
|
92934
|
+
"tempmail.com",
|
|
92935
|
+
"temp-mail.org",
|
|
92936
|
+
"temp-mail.io",
|
|
92937
|
+
"tempmailaddress.com",
|
|
92938
|
+
"tempmailo.com",
|
|
92939
|
+
"tempinbox.com",
|
|
92940
|
+
"throwawaymail.com",
|
|
92941
|
+
"yopmail.com",
|
|
92942
|
+
"yopmail.fr",
|
|
92943
|
+
"yopmail.net",
|
|
92944
|
+
"maildrop.cc",
|
|
92945
|
+
"trashmail.com",
|
|
92946
|
+
"trashmail.de",
|
|
92947
|
+
"trashmail.net",
|
|
92948
|
+
"trash-mail.com",
|
|
92949
|
+
"dispostable.com",
|
|
92950
|
+
"fakeinbox.com",
|
|
92951
|
+
"getnada.com",
|
|
92952
|
+
"mintemail.com",
|
|
92953
|
+
"mohmal.com",
|
|
92954
|
+
"moakt.cc",
|
|
92955
|
+
"formtests.info",
|
|
92956
|
+
"mailcatch.com",
|
|
92957
|
+
"mailnull.com",
|
|
92958
|
+
"spambog.com",
|
|
92959
|
+
"spambox.us",
|
|
92960
|
+
"spamgourmet.com",
|
|
92961
|
+
"emailondeck.com",
|
|
92962
|
+
"fakemailgenerator.com",
|
|
92963
|
+
"jetable.org",
|
|
92964
|
+
"mytrashmail.com",
|
|
92965
|
+
"owlpic.com",
|
|
92966
|
+
"rcpt.at",
|
|
92967
|
+
"trbvm.com"
|
|
92968
|
+
]);
|
|
92668
92969
|
// ../shared/dist/legal.js
|
|
92669
92970
|
var LEGAL_DOCUMENT_VERSIONS = {
|
|
92670
|
-
terms: "1.0.
|
|
92971
|
+
terms: "1.0.3",
|
|
92671
92972
|
aup: "1.0.1",
|
|
92672
|
-
privacy: "1.0.
|
|
92673
|
-
cookies: "1.0.
|
|
92674
|
-
dpa: "1.
|
|
92675
|
-
subprocessors: "1.
|
|
92676
|
-
dataPortability: "1.0"
|
|
92973
|
+
privacy: "1.0.4",
|
|
92974
|
+
cookies: "1.0.4",
|
|
92975
|
+
dpa: "1.1",
|
|
92976
|
+
subprocessors: "1.2",
|
|
92977
|
+
dataPortability: "1.0.4"
|
|
92677
92978
|
};
|
|
92678
92979
|
var CURRENT_TERMS_VERSION = LEGAL_DOCUMENT_VERSIONS.terms;
|
|
92679
92980
|
// ../shared/dist/legal-changes.js
|
|
@@ -92688,6 +92989,12 @@ var UPLOAD_SESSION_TTL_MS = 6 * 60 * 60 * 1000;
|
|
|
92688
92989
|
var UPLOAD_SESSION_MAX_LIFETIME_MS = 24 * 60 * 60 * 1000;
|
|
92689
92990
|
// ../shared/dist/logs.js
|
|
92690
92991
|
var MAX_LOG_SEARCH_LENGTH = 256;
|
|
92992
|
+
// ../shared/dist/oauth-scopes.js
|
|
92993
|
+
var DATA_ACCESS_SUFFIX = "records in your apps' databases, including data your app's users entered. Every record the assistant reads is sent to it and may be processed by its provider under the provider's terms. Revoke in Settings → Connections; copies already sent are not recalled.";
|
|
92994
|
+
var DATA_ACCESS_MODE_LABELS = {
|
|
92995
|
+
readwrite: `Read, create, change and delete ${DATA_ACCESS_SUFFIX}`,
|
|
92996
|
+
read: `Read ${DATA_ACCESS_SUFFIX}`
|
|
92997
|
+
};
|
|
92691
92998
|
// ../shared/dist/platform-env.js
|
|
92692
92999
|
var PERCHER_INJECTED_ENV_KEYS = new Set([
|
|
92693
93000
|
"NODE_ENV",
|
|
@@ -92713,6 +93020,23 @@ var PROXY_LOWERCASE_ALIASES = new Set([
|
|
|
92713
93020
|
// ../shared/dist/runtime.js
|
|
92714
93021
|
var DEFAULT_NODE_VERSION_MAJOR = "24";
|
|
92715
93022
|
var DEFAULT_NODE_VERSION_LABEL = `${DEFAULT_NODE_VERSION_MAJOR} LTS`;
|
|
93023
|
+
// ../shared/dist/signup-day.js
|
|
93024
|
+
var stockholmDate = new Intl.DateTimeFormat("sv-SE", {
|
|
93025
|
+
timeZone: "Europe/Stockholm",
|
|
93026
|
+
year: "numeric",
|
|
93027
|
+
month: "2-digit",
|
|
93028
|
+
day: "2-digit"
|
|
93029
|
+
});
|
|
93030
|
+
var stockholmClock = new Intl.DateTimeFormat("en-GB", {
|
|
93031
|
+
timeZone: "Europe/Stockholm",
|
|
93032
|
+
year: "numeric",
|
|
93033
|
+
month: "2-digit",
|
|
93034
|
+
day: "2-digit",
|
|
93035
|
+
hour: "2-digit",
|
|
93036
|
+
minute: "2-digit",
|
|
93037
|
+
second: "2-digit",
|
|
93038
|
+
hourCycle: "h23"
|
|
93039
|
+
});
|
|
92716
93040
|
// ../shared/dist/switches.js
|
|
92717
93041
|
var ONE = ["1"];
|
|
92718
93042
|
var TRUE = ["true"];
|
|
@@ -92796,6 +93120,7 @@ var SWITCHES = [
|
|
|
92796
93120
|
},
|
|
92797
93121
|
bool("PERCHER_ALLOW_NO_CAPTCHA", ["dashboard"], "allow production without Turnstile", ONE),
|
|
92798
93122
|
bool("PERCHER_ALLOW_UNVERIFIED_SIGNUP", ["dashboard"], "allow production without Resend", ONE),
|
|
93123
|
+
bool("PERCHER_DASHBOARD_SECRET_BUILD", ["dashboard"], "allow an ephemeral BetterAuth key during `next build` only, never at runtime", ONE),
|
|
92799
93124
|
bool("PERCHER_ALLOW_NO_ALERTING", ["api"], "boot without an alert channel", ONE),
|
|
92800
93125
|
{
|
|
92801
93126
|
kind: "presence",
|
|
@@ -106437,7 +106762,7 @@ var ENV_NAME_SHAPE = "UPPER_SNAKE_CASE, at most 256 characters";
|
|
|
106437
106762
|
var buildSchema = exports_external.object({
|
|
106438
106763
|
command: exports_external.string().optional(),
|
|
106439
106764
|
output: exports_external.string().refine((v) => !v.startsWith("/"), "must be a relative path (no leading slash)").optional(),
|
|
106440
|
-
pass_env: exports_external.array(exports_external.string().regex(ENV_NAME_RE2, `must be a valid env var name (${ENV_NAME_SHAPE})`).refine((name) => !name.startsWith("BUILDKIT_"), "BUILDKIT_*
|
|
106765
|
+
pass_env: exports_external.array(exports_external.string().regex(ENV_NAME_RE2, `must be a valid env var name (${ENV_NAME_SHAPE})`).refine((name) => !name.startsWith("BUILDKIT_") && name !== "PERCHER_BUILD_SECRET_DIGEST", "BUILDKIT_* and PERCHER_BUILD_SECRET_DIGEST are reserved by Percher and cannot be passed to the build")).max(50, "at most 50 build env vars can be exposed").optional()
|
|
106441
106766
|
}).strict();
|
|
106442
106767
|
var webSchema = exports_external.object({
|
|
106443
106768
|
port: exports_external.number().int().min(1024).max(65535),
|
|
@@ -107138,7 +107463,7 @@ var LEGACY_AUDIT_REQUIRED_CONJUNCTS = [
|
|
|
107138
107463
|
"volumes_attributed",
|
|
107139
107464
|
"scans_complete",
|
|
107140
107465
|
"runtime_evidence_complete",
|
|
107141
|
-
"
|
|
107466
|
+
"security_attestation_complete",
|
|
107142
107467
|
"launch_gate_ready"
|
|
107143
107468
|
];
|
|
107144
107469
|
function legacyAuditIsGreen(result) {
|
|
@@ -107774,20 +108099,32 @@ function manifestStarter({ name, themeColorHex }) {
|
|
|
107774
108099
|
theme_color: themeColorHex
|
|
107775
108100
|
}, null, 2);
|
|
107776
108101
|
}
|
|
107777
|
-
function serviceWorkerStarter() {
|
|
107778
|
-
|
|
107779
|
-
|
|
107780
|
-
|
|
108102
|
+
function serviceWorkerStarter(assets = []) {
|
|
108103
|
+
if (assets.some((path) => !path.startsWith("/") || path.startsWith("//") || path.includes("\\"))) {
|
|
108104
|
+
throw new Error("Offline assets must be same-origin absolute paths");
|
|
108105
|
+
}
|
|
108106
|
+
return `// sw.js — public offline shell. Serve from /sw.js.
|
|
108107
|
+
// Add public assets, e.g. ["/offline.html", "/app.js", "/app.css"]. Never add private pages or API data.
|
|
108108
|
+
// Include "/" only if the page is public and identical for signed-in and anonymous visitors.
|
|
108109
|
+
// Bump CACHE whenever the asset list or its content changes. Test an offline reload.
|
|
108110
|
+
const CACHE = "percher-public-shell-v1";
|
|
108111
|
+
const SHELL = ${JSON.stringify(assets)};
|
|
107781
108112
|
|
|
107782
108113
|
self.addEventListener("install", (event) => {
|
|
107783
|
-
event.waitUntil(caches.open(CACHE).then((cache) =>
|
|
108114
|
+
event.waitUntil(caches.open(CACHE).then((cache) => Promise.all(SHELL.map(async (path) => {
|
|
108115
|
+
const response = await fetch(path, { credentials: "omit", redirect: "error" });
|
|
108116
|
+
if (!response.ok || /private|no-store/i.test(response.headers.get("cache-control") || "")) {
|
|
108117
|
+
throw new Error("Offline asset is unavailable or private: " + path);
|
|
108118
|
+
}
|
|
108119
|
+
await cache.put(path, response);
|
|
108120
|
+
}))));
|
|
107784
108121
|
self.skipWaiting();
|
|
107785
108122
|
});
|
|
107786
108123
|
|
|
107787
108124
|
self.addEventListener("activate", (event) => {
|
|
107788
108125
|
event.waitUntil(
|
|
107789
108126
|
caches.keys().then((keys) =>
|
|
107790
|
-
Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))),
|
|
108127
|
+
Promise.all(keys.filter((k) => k.startsWith("percher-public-shell-") && k !== CACHE).map((k) => caches.delete(k))),
|
|
107791
108128
|
),
|
|
107792
108129
|
);
|
|
107793
108130
|
self.clients.claim();
|
|
@@ -107795,8 +108132,10 @@ self.addEventListener("activate", (event) => {
|
|
|
107795
108132
|
|
|
107796
108133
|
self.addEventListener("fetch", (event) => {
|
|
107797
108134
|
if (event.request.method !== "GET") return;
|
|
108135
|
+
const url = new URL(event.request.url);
|
|
108136
|
+
if (url.origin !== self.location.origin || !SHELL.includes(url.pathname + url.search)) return;
|
|
107798
108137
|
event.respondWith(
|
|
107799
|
-
caches.match(event.request).then((cached) => cached || fetch(event.request)),
|
|
108138
|
+
caches.open(CACHE).then((cache) => cache.match(event.request)).then((cached) => cached || fetch(event.request)),
|
|
107800
108139
|
);
|
|
107801
108140
|
});`;
|
|
107802
108141
|
}
|
|
@@ -107965,17 +108304,17 @@ async function claim(ctx, input = {}) {
|
|
|
107965
108304
|
};
|
|
107966
108305
|
}
|
|
107967
108306
|
// ../core/dist/commands/create.js
|
|
107968
|
-
import { join as
|
|
108307
|
+
import { join as join9, resolve as resolve5 } from "node:path";
|
|
107969
108308
|
|
|
107970
108309
|
// ../core/dist/templates.js
|
|
107971
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
107972
|
-
import { basename as basename2, join as
|
|
107973
|
-
var __dirname = "C:\\dev\\Percher\\packages\\core\\dist";
|
|
108310
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readdirSync, readFileSync as readFileSync6, statSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
108311
|
+
import { basename as basename2, join as join8, normalize, relative as relative2, resolve as resolve4 } from "node:path";
|
|
108312
|
+
var __dirname = "C:\\dev\\Percher-npm-final-release-20261018\\packages\\core\\dist";
|
|
107974
108313
|
var TEMPLATES_DIR = resolve4(import.meta.dirname ?? __dirname, "../templates");
|
|
107975
108314
|
var PLACEHOLDER = "__APP_NAME__";
|
|
107976
108315
|
function listTemplates() {
|
|
107977
108316
|
return readdirSync(TEMPLATES_DIR).filter((name) => {
|
|
107978
|
-
const full =
|
|
108317
|
+
const full = join8(TEMPLATES_DIR, name);
|
|
107979
108318
|
return statSync(full).isDirectory();
|
|
107980
108319
|
});
|
|
107981
108320
|
}
|
|
@@ -107992,13 +108331,13 @@ function scaffoldTemplate(input) {
|
|
|
107992
108331
|
throw new Error(`Target directory "${absTarget}" is not empty. Use --force to overwrite.`);
|
|
107993
108332
|
}
|
|
107994
108333
|
}
|
|
107995
|
-
const srcDir =
|
|
108334
|
+
const srcDir = join8(TEMPLATES_DIR, template);
|
|
107996
108335
|
const files = [];
|
|
107997
108336
|
function copyDir(src, dest) {
|
|
107998
|
-
|
|
108337
|
+
mkdirSync6(dest, { recursive: true });
|
|
107999
108338
|
for (const entry of readdirSync(src)) {
|
|
108000
|
-
const srcPath =
|
|
108001
|
-
const destPath =
|
|
108339
|
+
const srcPath = join8(src, entry);
|
|
108340
|
+
const destPath = join8(dest, entry);
|
|
108002
108341
|
const rel = relative2(absTarget, normalize(destPath));
|
|
108003
108342
|
if (rel.startsWith("..") || resolve4(destPath) === resolve4(absTarget, "..", basename2(absTarget))) {
|
|
108004
108343
|
throw new Error(`Template contains path traversal: ${entry}`);
|
|
@@ -108009,11 +108348,11 @@ function scaffoldTemplate(input) {
|
|
|
108009
108348
|
if (existsSync5(destPath) && !force) {
|
|
108010
108349
|
continue;
|
|
108011
108350
|
}
|
|
108012
|
-
let content =
|
|
108351
|
+
let content = readFileSync6(srcPath, "utf-8");
|
|
108013
108352
|
content = content.replaceAll(PLACEHOLDER, appName);
|
|
108014
108353
|
content = content.replace(/\r\n/g, `
|
|
108015
108354
|
`);
|
|
108016
|
-
|
|
108355
|
+
writeFileSync6(destPath, content, "utf-8");
|
|
108017
108356
|
files.push(relative2(absTarget, destPath).replace(/\\/g, "/"));
|
|
108018
108357
|
}
|
|
108019
108358
|
}
|
|
@@ -108046,7 +108385,7 @@ async function create(ctx, input) {
|
|
|
108046
108385
|
});
|
|
108047
108386
|
}
|
|
108048
108387
|
} else {
|
|
108049
|
-
targetDir =
|
|
108388
|
+
targetDir = join9(ctx.cwd, input.name);
|
|
108050
108389
|
}
|
|
108051
108390
|
try {
|
|
108052
108391
|
const result = scaffoldTemplate({
|
|
@@ -108101,226 +108440,6 @@ async function dashboard(ctx, input = {}) {
|
|
|
108101
108440
|
await ctx.openUrl(url2);
|
|
108102
108441
|
return url2;
|
|
108103
108442
|
}
|
|
108104
|
-
// ../core/dist/commands/data.js
|
|
108105
|
-
var dataInputSchema = exports_external.object({
|
|
108106
|
-
app: exports_external.string().optional(),
|
|
108107
|
-
json: exports_external.boolean().optional()
|
|
108108
|
-
});
|
|
108109
|
-
async function data(ctx, input = {}) {
|
|
108110
|
-
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108111
|
-
if (!name) {
|
|
108112
|
-
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108113
|
-
code: "data.no-app",
|
|
108114
|
-
hint: "Pass an app name or run from a directory with percher.toml."
|
|
108115
|
-
});
|
|
108116
|
-
}
|
|
108117
|
-
const status = await ctx.client.data.getStatus(name);
|
|
108118
|
-
const adminLink = await ctx.client.data.getAdminLink(name);
|
|
108119
|
-
let collections = [];
|
|
108120
|
-
let stats = { collections: 0, totalRecords: 0 };
|
|
108121
|
-
let warning = null;
|
|
108122
|
-
try {
|
|
108123
|
-
const cols = await ctx.client.data.getCollections(name);
|
|
108124
|
-
collections = cols.map((c) => ({ name: c.name, type: c.type }));
|
|
108125
|
-
stats = await ctx.client.data.getStats(name);
|
|
108126
|
-
} catch (err) {
|
|
108127
|
-
const code = err.code;
|
|
108128
|
-
if (code === "PB_AUTH_FAILED") {
|
|
108129
|
-
warning = `Could not authenticate with PocketBase — collections + stats unavailable. Try \`percher data reset-superuser ${name}\` to rotate the credentials.`;
|
|
108130
|
-
} else {
|
|
108131
|
-
throw err;
|
|
108132
|
-
}
|
|
108133
|
-
}
|
|
108134
|
-
return {
|
|
108135
|
-
mode: status.mode,
|
|
108136
|
-
status: status.status,
|
|
108137
|
-
version: status.version ?? null,
|
|
108138
|
-
collections,
|
|
108139
|
-
stats,
|
|
108140
|
-
adminUrl: adminLink.adminUrl ?? null,
|
|
108141
|
-
warning
|
|
108142
|
-
};
|
|
108143
|
-
}
|
|
108144
|
-
// ../core/dist/commands/data-export.js
|
|
108145
|
-
import { resolve as resolve6 } from "node:path";
|
|
108146
|
-
var dataExportInputSchema = exports_external.object({
|
|
108147
|
-
app: exports_external.string().optional().describe("App name or id. Defaults to the app in percher.toml."),
|
|
108148
|
-
out: exports_external.string().optional().describe("Output file path. Defaults to ./<app>-pb-<timestamp>.tar.gz in the current directory.")
|
|
108149
|
-
});
|
|
108150
|
-
async function dataExport(ctx, input) {
|
|
108151
|
-
const appName = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108152
|
-
if (!appName) {
|
|
108153
|
-
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108154
|
-
code: "data-export.no-app",
|
|
108155
|
-
hint: "Pass an app name with --app <name> or run from a directory with percher.toml."
|
|
108156
|
-
});
|
|
108157
|
-
}
|
|
108158
|
-
ctx.status?.(`Exporting ${appName} data...`);
|
|
108159
|
-
const stamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
108160
|
-
const fileName = input.out ?? `${appName}-pb-${stamp}.tar.gz`;
|
|
108161
|
-
const path = resolve6(ctx.cwd, fileName);
|
|
108162
|
-
const res = await ctx.client.apps.streamDataExport(appName);
|
|
108163
|
-
const bytes = await writeGzipResponseToFileAtomic(res, path);
|
|
108164
|
-
return {
|
|
108165
|
-
app: appName,
|
|
108166
|
-
path,
|
|
108167
|
-
bytes,
|
|
108168
|
-
exportedAt: new Date().toISOString()
|
|
108169
|
-
};
|
|
108170
|
-
}
|
|
108171
|
-
// ../core/dist/commands/data-oauth.js
|
|
108172
|
-
var dataOauthInputSchema = exports_external.object({
|
|
108173
|
-
app: exports_external.string().optional(),
|
|
108174
|
-
provider: exports_external.string().default("google"),
|
|
108175
|
-
clientId: exports_external.string().optional(),
|
|
108176
|
-
clientSecret: exports_external.string().optional(),
|
|
108177
|
-
remove: exports_external.boolean().optional(),
|
|
108178
|
-
json: exports_external.boolean().optional()
|
|
108179
|
-
});
|
|
108180
|
-
async function dataOauth(ctx, input = { provider: "google" }) {
|
|
108181
|
-
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108182
|
-
if (!name) {
|
|
108183
|
-
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108184
|
-
code: "data.no-app",
|
|
108185
|
-
hint: "Pass an app name or run from a directory with percher.toml."
|
|
108186
|
-
});
|
|
108187
|
-
}
|
|
108188
|
-
const provider = input.provider || "google";
|
|
108189
|
-
if (input.remove) {
|
|
108190
|
-
await ctx.client.data.removeOAuthProvider(name, provider);
|
|
108191
|
-
return { action: "removed", provider };
|
|
108192
|
-
}
|
|
108193
|
-
if (input.clientId && input.clientSecret) {
|
|
108194
|
-
const res = await ctx.client.data.setOAuthProvider(name, {
|
|
108195
|
-
provider,
|
|
108196
|
-
clientId: input.clientId,
|
|
108197
|
-
clientSecret: input.clientSecret
|
|
108198
|
-
});
|
|
108199
|
-
return {
|
|
108200
|
-
action: "set",
|
|
108201
|
-
provider: res.provider,
|
|
108202
|
-
redirectUri: res.redirectUri,
|
|
108203
|
-
note: res.note
|
|
108204
|
-
};
|
|
108205
|
-
}
|
|
108206
|
-
const status = await ctx.client.data.getOAuthStatus(name);
|
|
108207
|
-
return {
|
|
108208
|
-
action: "status",
|
|
108209
|
-
provider,
|
|
108210
|
-
providers: status.providers,
|
|
108211
|
-
redirectUri: status.redirectUri
|
|
108212
|
-
};
|
|
108213
|
-
}
|
|
108214
|
-
// ../core/dist/commands/delete.js
|
|
108215
|
-
var deleteInputSchema = exports_external.object({
|
|
108216
|
-
app: exports_external.string().optional().describe("App name to delete (defaults to percher.toml app name)"),
|
|
108217
|
-
confirm: exports_external.boolean().describe("Must be true to confirm deletion. This is a destructive operation that permanently removes the app, its container, database, domains, env vars, and deploy history.")
|
|
108218
|
-
});
|
|
108219
|
-
async function deleteApp(ctx, input) {
|
|
108220
|
-
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108221
|
-
if (!name) {
|
|
108222
|
-
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108223
|
-
code: "env.no-app",
|
|
108224
|
-
hint: "Pass an app name or run from a directory with percher.toml."
|
|
108225
|
-
});
|
|
108226
|
-
}
|
|
108227
|
-
if (!input.confirm) {
|
|
108228
|
-
throw new PercherCoreError(`Deletion requires explicit confirmation. Set confirm: true to delete "${name}" permanently.`, {
|
|
108229
|
-
code: "delete.confirmation-required",
|
|
108230
|
-
hint: `This will permanently delete the app "${name}" and all its data. Pass confirm: true to proceed.`
|
|
108231
|
-
});
|
|
108232
|
-
}
|
|
108233
|
-
await ctx.client.apps.delete(name);
|
|
108234
|
-
}
|
|
108235
|
-
// ../core/dist/commands/deploy-repo.js
|
|
108236
|
-
init_dist();
|
|
108237
|
-
|
|
108238
|
-
// ../core/dist/poll-deployment.js
|
|
108239
|
-
init_dist();
|
|
108240
|
-
class DeployPollLostContactError extends PercherCoreError {
|
|
108241
|
-
deploymentId;
|
|
108242
|
-
constructor(message, deploymentId, appName, options) {
|
|
108243
|
-
super(message, {
|
|
108244
|
-
code: "push.lost-contact",
|
|
108245
|
-
hint: `The deploy may already be live. Check with: percher deploys ${appName}`,
|
|
108246
|
-
cause: options?.cause
|
|
108247
|
-
});
|
|
108248
|
-
this.deploymentId = deploymentId;
|
|
108249
|
-
this.name = "DeployPollLostContactError";
|
|
108250
|
-
}
|
|
108251
|
-
}
|
|
108252
|
-
function isTransientPollError(err) {
|
|
108253
|
-
if (isTransientNetworkError(err))
|
|
108254
|
-
return true;
|
|
108255
|
-
if (err instanceof PercherApiError)
|
|
108256
|
-
return err.status === 502 || err.status === 503 || err.status === 504;
|
|
108257
|
-
return err instanceof TypeError && /terminated/i.test(err.message);
|
|
108258
|
-
}
|
|
108259
|
-
async function pollDeployment(opts) {
|
|
108260
|
-
const terminal = opts.terminal ?? ["live", "failed"];
|
|
108261
|
-
const intervalMs = opts.intervalMs ?? 2000;
|
|
108262
|
-
const timeoutMs = opts.timeoutMs ?? TIMEOUTS.clientPublishPoll;
|
|
108263
|
-
const maxRetries = opts.maxRetries ?? Number.POSITIVE_INFINITY;
|
|
108264
|
-
const retryBudgetMs = opts.retryBudgetMs ?? 5 * 60000;
|
|
108265
|
-
let deployment = opts.initial;
|
|
108266
|
-
const startedAt = Date.now();
|
|
108267
|
-
const seenEventIds = new Set;
|
|
108268
|
-
if (opts.onEvent) {
|
|
108269
|
-
await drainNewEvents(opts, deployment.id, seenEventIds);
|
|
108270
|
-
}
|
|
108271
|
-
while (!terminal.includes(deployment.status)) {
|
|
108272
|
-
if (Date.now() - startedAt > timeoutMs) {
|
|
108273
|
-
opts.onTimeout(deployment);
|
|
108274
|
-
}
|
|
108275
|
-
opts.onTick?.(deployment);
|
|
108276
|
-
await new Promise((r) => setTimeout(r, intervalMs));
|
|
108277
|
-
let attempt = 0;
|
|
108278
|
-
let streakStartedAt = 0;
|
|
108279
|
-
let polled = false;
|
|
108280
|
-
while (!polled) {
|
|
108281
|
-
try {
|
|
108282
|
-
deployment = await opts.ctx.client.apps.getDeployment(opts.appId, deployment.id);
|
|
108283
|
-
polled = true;
|
|
108284
|
-
} catch (err) {
|
|
108285
|
-
attempt++;
|
|
108286
|
-
if (!isTransientPollError(err))
|
|
108287
|
-
throw err;
|
|
108288
|
-
if (attempt === 1) {
|
|
108289
|
-
streakStartedAt = Date.now();
|
|
108290
|
-
opts.ctx.status("Lost contact with Percher; retrying while the deploy continues...");
|
|
108291
|
-
}
|
|
108292
|
-
if (Date.now() - startedAt > timeoutMs)
|
|
108293
|
-
opts.onTimeout(deployment);
|
|
108294
|
-
if (attempt >= maxRetries || Date.now() - streakStartedAt >= retryBudgetMs) {
|
|
108295
|
-
const msg = err.message ?? String(err);
|
|
108296
|
-
throw new DeployPollLostContactError(`${msg}
|
|
108297
|
-
|
|
108298
|
-
The deploy may already be live — contact with Percher was lost mid-poll. Check with: percher deploys ${opts.appName}`, deployment.id, opts.appName, { cause: err });
|
|
108299
|
-
}
|
|
108300
|
-
const backoff = (opts.backoffMs ?? ((n) => Math.min(1000 * 2 ** (n - 1), 15000)))(attempt);
|
|
108301
|
-
await new Promise((r) => setTimeout(r, backoff));
|
|
108302
|
-
}
|
|
108303
|
-
}
|
|
108304
|
-
if (opts.onEvent) {
|
|
108305
|
-
await drainNewEvents(opts, deployment.id, seenEventIds);
|
|
108306
|
-
}
|
|
108307
|
-
}
|
|
108308
|
-
return deployment;
|
|
108309
|
-
}
|
|
108310
|
-
async function drainNewEvents(opts, deployId, seenEventIds) {
|
|
108311
|
-
if (!opts.onEvent)
|
|
108312
|
-
return;
|
|
108313
|
-
try {
|
|
108314
|
-
const { events } = await opts.ctx.client.apps.getDeployEvents(opts.appId, deployId);
|
|
108315
|
-
for (const event of events) {
|
|
108316
|
-
if (seenEventIds.has(event.id))
|
|
108317
|
-
continue;
|
|
108318
|
-
seenEventIds.add(event.id);
|
|
108319
|
-
opts.onEvent(event);
|
|
108320
|
-
}
|
|
108321
|
-
} catch {}
|
|
108322
|
-
}
|
|
108323
|
-
|
|
108324
108443
|
// ../core/dist/untrusted.js
|
|
108325
108444
|
import { relative as relative3 } from "node:path";
|
|
108326
108445
|
function boundedSeconds(value, maxSeconds = 86400) {
|
|
@@ -108459,6 +108578,323 @@ function projectRelative(cwd, abs) {
|
|
|
108459
108578
|
return isSafeRelativePath(rel) ? rel : null;
|
|
108460
108579
|
}
|
|
108461
108580
|
|
|
108581
|
+
// ../core/dist/commands/data.js
|
|
108582
|
+
var dataInputSchema = exports_external.object({
|
|
108583
|
+
app: exports_external.string().optional(),
|
|
108584
|
+
json: exports_external.boolean().optional()
|
|
108585
|
+
});
|
|
108586
|
+
async function data(ctx, input = {}) {
|
|
108587
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108588
|
+
if (!name) {
|
|
108589
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108590
|
+
code: "data.no-app",
|
|
108591
|
+
hint: "Pass an app name or run from a directory with percher.toml."
|
|
108592
|
+
});
|
|
108593
|
+
}
|
|
108594
|
+
const status = await ctx.client.data.getStatus(name);
|
|
108595
|
+
const adminLink = await ctx.client.data.getAdminLink(name);
|
|
108596
|
+
let collections = [];
|
|
108597
|
+
let stats = { collections: 0, totalRecords: 0 };
|
|
108598
|
+
let warning = null;
|
|
108599
|
+
try {
|
|
108600
|
+
const cols = await ctx.client.data.getCollections(name);
|
|
108601
|
+
collections = cols.map((c) => ({ name: c.name, type: c.type }));
|
|
108602
|
+
stats = await ctx.client.data.getStats(name);
|
|
108603
|
+
} catch (err) {
|
|
108604
|
+
const code = err.code;
|
|
108605
|
+
if (code === "PB_AUTH_FAILED") {
|
|
108606
|
+
const ref = appRef(name) ?? "<app>";
|
|
108607
|
+
const verdict = err.extra?.verdict;
|
|
108608
|
+
warning = verdict === "rejected" ? `Percher has no working PocketBase admin credentials for this app; collections and counts are unavailable. The app owner can issue new ones with \`percher data reset-superuser ${ref}\`.` : `PocketBase authentication failed; collections and counts are unavailable. Retry \`percher data ${ref}\`; if this continues, contact support.`;
|
|
108609
|
+
} else {
|
|
108610
|
+
throw err;
|
|
108611
|
+
}
|
|
108612
|
+
}
|
|
108613
|
+
return {
|
|
108614
|
+
mode: status.mode,
|
|
108615
|
+
status: status.status,
|
|
108616
|
+
version: status.version ?? null,
|
|
108617
|
+
collections,
|
|
108618
|
+
stats,
|
|
108619
|
+
adminUrl: adminLink.adminUrl ?? null,
|
|
108620
|
+
warning
|
|
108621
|
+
};
|
|
108622
|
+
}
|
|
108623
|
+
// ../core/dist/commands/data-export.js
|
|
108624
|
+
import { resolve as resolve6 } from "node:path";
|
|
108625
|
+
var dataExportInputSchema = exports_external.object({
|
|
108626
|
+
app: exports_external.string().optional().describe("App name or id. Defaults to the app in percher.toml."),
|
|
108627
|
+
out: exports_external.string().optional().describe("Output file path. Defaults to ./<app>-pb-<timestamp>.tar.gz in the current directory.")
|
|
108628
|
+
});
|
|
108629
|
+
async function dataExport(ctx, input) {
|
|
108630
|
+
const appName = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108631
|
+
if (!appName) {
|
|
108632
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108633
|
+
code: "data-export.no-app",
|
|
108634
|
+
hint: "Pass an app name with --app <name> or run from a directory with percher.toml."
|
|
108635
|
+
});
|
|
108636
|
+
}
|
|
108637
|
+
ctx.status?.(`Exporting ${appName} data...`);
|
|
108638
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
108639
|
+
const fileName = input.out ?? `${appName}-pb-${stamp}.tar.gz`;
|
|
108640
|
+
const path = resolve6(ctx.cwd, fileName);
|
|
108641
|
+
const res = await ctx.client.apps.streamDataExport(appName);
|
|
108642
|
+
const bytes = await writeGzipResponseToFileAtomic(res, path);
|
|
108643
|
+
return {
|
|
108644
|
+
app: appName,
|
|
108645
|
+
path,
|
|
108646
|
+
bytes,
|
|
108647
|
+
exportedAt: new Date().toISOString()
|
|
108648
|
+
};
|
|
108649
|
+
}
|
|
108650
|
+
// ../core/dist/commands/data-oauth.js
|
|
108651
|
+
var dataOauthInputSchema = exports_external.object({
|
|
108652
|
+
app: exports_external.string().optional(),
|
|
108653
|
+
provider: exports_external.string().default("google"),
|
|
108654
|
+
clientId: exports_external.string().optional(),
|
|
108655
|
+
clientSecret: exports_external.string().optional(),
|
|
108656
|
+
remove: exports_external.boolean().optional(),
|
|
108657
|
+
json: exports_external.boolean().optional()
|
|
108658
|
+
});
|
|
108659
|
+
async function dataOauth(ctx, input = { provider: "google" }) {
|
|
108660
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
108661
|
+
if (!name) {
|
|
108662
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
108663
|
+
code: "data.no-app",
|
|
108664
|
+
hint: "Pass an app name or run from a directory with percher.toml."
|
|
108665
|
+
});
|
|
108666
|
+
}
|
|
108667
|
+
const provider = input.provider || "google";
|
|
108668
|
+
if (input.remove) {
|
|
108669
|
+
await ctx.client.data.removeOAuthProvider(name, provider);
|
|
108670
|
+
return { action: "removed", provider };
|
|
108671
|
+
}
|
|
108672
|
+
if (input.clientId && input.clientSecret) {
|
|
108673
|
+
const res = await ctx.client.data.setOAuthProvider(name, {
|
|
108674
|
+
provider,
|
|
108675
|
+
clientId: input.clientId,
|
|
108676
|
+
clientSecret: input.clientSecret
|
|
108677
|
+
});
|
|
108678
|
+
return {
|
|
108679
|
+
action: "set",
|
|
108680
|
+
provider: res.provider,
|
|
108681
|
+
redirectUri: res.redirectUri,
|
|
108682
|
+
note: res.note
|
|
108683
|
+
};
|
|
108684
|
+
}
|
|
108685
|
+
const status = await ctx.client.data.getOAuthStatus(name);
|
|
108686
|
+
return {
|
|
108687
|
+
action: "status",
|
|
108688
|
+
provider,
|
|
108689
|
+
providers: status.providers,
|
|
108690
|
+
redirectUri: status.redirectUri
|
|
108691
|
+
};
|
|
108692
|
+
}
|
|
108693
|
+
// ../core/dist/commands/data-records.js
|
|
108694
|
+
init_dist();
|
|
108695
|
+
|
|
108696
|
+
// ../core/dist/data-recovery.js
|
|
108697
|
+
init_dist();
|
|
108698
|
+
|
|
108699
|
+
// ../core/dist/structured-error-codes.js
|
|
108700
|
+
var MAPPINGS = {
|
|
108701
|
+
PB_PROVISION_FAILED: {
|
|
108702
|
+
errorClass: "pb_provision_failed",
|
|
108703
|
+
phase: "infra",
|
|
108704
|
+
cause: "pb_provision_failed",
|
|
108705
|
+
title: "Database admin setup failed",
|
|
108706
|
+
explanation: () => "The platform could not set up the database admin account.",
|
|
108707
|
+
suggestion: "Publishing again after the platform failure is resolved is safe."
|
|
108708
|
+
},
|
|
108709
|
+
BUILD_SECRET_KEY_UNAVAILABLE: {
|
|
108710
|
+
errorClass: "build_secrets_unavailable",
|
|
108711
|
+
phase: "infra",
|
|
108712
|
+
cause: "build_secret_key_unavailable",
|
|
108713
|
+
title: "Percher could not protect build secrets",
|
|
108714
|
+
explanation: () => "Percher's key for build secrets is unavailable, so it refused the build rather than run it without them. This is a platform issue and does not count against your app.",
|
|
108715
|
+
suggestion: "Contact support. Removing the non-public keys from [build] pass_env lets the build run without them."
|
|
108716
|
+
},
|
|
108717
|
+
BUILD_SECRETS_UNSUPPORTED_NIXPACKS: {
|
|
108718
|
+
errorClass: "build_secrets_unavailable",
|
|
108719
|
+
phase: "infra",
|
|
108720
|
+
cause: "build_secrets_unsupported_nixpacks",
|
|
108721
|
+
title: "This builder cannot mount build secrets",
|
|
108722
|
+
explanation: () => "Percher is building this app with its fallback builder, which cannot keep build secrets out of the image, so it refused the build. It does not count against your app.",
|
|
108723
|
+
suggestion: "Remove the non-public keys from [build] pass_env, or deploy again later."
|
|
108724
|
+
},
|
|
108725
|
+
SHARED_NETWORK_FORBIDDEN: {
|
|
108726
|
+
errorClass: "infra_unavailable",
|
|
108727
|
+
phase: "infra",
|
|
108728
|
+
cause: "shared_network_forbidden",
|
|
108729
|
+
title: "Percher refused unsafe network placement",
|
|
108730
|
+
explanation: () => "This app is still on Percher's shared bridge. Percher refused to start another container there. This is a platform issue and does not count against your app.",
|
|
108731
|
+
suggestion: "Contact support. A Percher operator must migrate the app to its own network before you retry."
|
|
108732
|
+
},
|
|
108733
|
+
PLATFORM_DISK_LOW: {
|
|
108734
|
+
errorClass: "platform_at_capacity",
|
|
108735
|
+
phase: "infra",
|
|
108736
|
+
cause: "disk_headroom_exhausted",
|
|
108737
|
+
title: "Platform storage is too low",
|
|
108738
|
+
explanation: () => "Percher paused new deploys: the platform is nearly out of disk. Not your app — nothing to change. Deployed apps keep running; only new deploys are paused.",
|
|
108739
|
+
suggestion: "The operator is alerted automatically. Run `percher publish` again in ~15 min; this failure does not count against your app. Still failing after an hour: https://percher.app/status"
|
|
108740
|
+
},
|
|
108741
|
+
PLATFORM_DISK_UNKNOWN: {
|
|
108742
|
+
errorClass: "platform_at_capacity",
|
|
108743
|
+
phase: "infra",
|
|
108744
|
+
cause: "disk_state_unreadable",
|
|
108745
|
+
title: "Platform storage state is unknown",
|
|
108746
|
+
explanation: () => "Percher paused new deploys: it can't read how much disk is left, and won't assume there's room. Not your app. Deployed apps have not been stopped by this.",
|
|
108747
|
+
suggestion: "Run `percher publish` again in ~5 min; this failure does not count against your app. Still failing after 15 min: https://percher.app/status"
|
|
108748
|
+
},
|
|
108749
|
+
PLAN_POOL_EXCEEDED: {
|
|
108750
|
+
errorClass: "plan_pool_exceeded",
|
|
108751
|
+
phase: "start",
|
|
108752
|
+
cause: "plan_pool_exceeded",
|
|
108753
|
+
title: "Plan resource pool is full",
|
|
108754
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} The platform is fine — the account is at its plan's limit.` : "This deploy would commit more RAM, vCPU or disk than your plan's pool allows across all your apps. The platform is fine — the account is at its limit.",
|
|
108755
|
+
suggestion: "Reduce `[resources]` in this app's percher.toml, delete an app you no longer need, or upgrade at https://percher.app/account/billing. Retrying unchanged will fail the same way."
|
|
108756
|
+
},
|
|
108757
|
+
PLACEMENT_UNDETERMINED: {
|
|
108758
|
+
errorClass: "infra_unavailable",
|
|
108759
|
+
phase: "infra",
|
|
108760
|
+
cause: "placement_undetermined",
|
|
108761
|
+
title: "Percher could not place your app's container",
|
|
108762
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} This is a platform-side read of Percher's own container placement, not anything in your app.` : "Percher could not read which internal network this app's current containers are on, and refused to guess rather than risk splitting the app from its database across two networks.",
|
|
108763
|
+
suggestion: "Nothing to change in your app. Retry in a minute; if it persists, the platform is having trouble reaching its container daemon and Percher's operators are alerted."
|
|
108764
|
+
},
|
|
108765
|
+
PLATFORM_MEMORY_LOW: {
|
|
108766
|
+
errorClass: "platform_at_capacity",
|
|
108767
|
+
phase: "infra",
|
|
108768
|
+
cause: "box_admission_rejected",
|
|
108769
|
+
title: "Platform is at capacity",
|
|
108770
|
+
explanation: (raw) => raw ? `Percher couldn't fit this deploy on the box right now: ${trimMessage(raw)} Not your app — nothing to change. Deployed apps keep running.` : "Percher couldn't fit this deploy on the box right now — the admission gate refused to start the container. Not your app — nothing to change. Deployed apps keep running.",
|
|
108771
|
+
suggestion: "Run `percher publish` again in a few minutes; capacity frees up as other deploys finish, and this failure does not count against your app. Still failing after an hour: https://percher.app/status"
|
|
108772
|
+
},
|
|
108773
|
+
PB_BRIDGE_UNAVAILABLE: {
|
|
108774
|
+
errorClass: "infra_unavailable",
|
|
108775
|
+
phase: "infra",
|
|
108776
|
+
cause: "pb_bridge_unreachable",
|
|
108777
|
+
title: "PocketBase is unreachable from the platform",
|
|
108778
|
+
explanation: (raw) => raw ? `Percher could not reach your app's database through its internal bridge: ${trimMessage(raw)}. This is a platform-side issue — your data and your code are both fine.` : "Percher could not reach your app's database through its internal bridge. This is a platform-side issue — your data and your code are both fine.",
|
|
108779
|
+
suggestion: "Wait a minute and run `percher publish` again; this failure does not count against your app. Your data was not touched — the platform could not read it, which is not the same as it being missing. Still failing after 15 min: https://percher.app/status"
|
|
108780
|
+
},
|
|
108781
|
+
PB_ROTATION_UNVERIFIED: {
|
|
108782
|
+
errorClass: "infra_unavailable",
|
|
108783
|
+
phase: "infra",
|
|
108784
|
+
cause: "pb_rotation_unverified",
|
|
108785
|
+
title: "PocketBase admin password was rotated but not confirmed",
|
|
108786
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} The rotation itself ran, so the previously stored admin password may now be stale. Your app data was not modified — only the admin credential changed.` : "Percher rotated your app's PocketBase admin password, then could not confirm the rotation. The previously stored admin password may now be stale. Your app data was not modified — only the admin credential changed.",
|
|
108787
|
+
suggestion: "Run the superuser reset again (`percher data reset-superuser` or the dashboard's reset button) — the rotation is idempotent, and a successful re-run stores a fresh working credential. This failure does not count against your app."
|
|
108788
|
+
},
|
|
108789
|
+
PB_OPERATION_BUSY: {
|
|
108790
|
+
errorClass: "pb_operation_busy",
|
|
108791
|
+
phase: "start",
|
|
108792
|
+
cause: "pb_backup_restore_busy",
|
|
108793
|
+
title: "PocketBase is finishing another data operation",
|
|
108794
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} The operation is scoped to this app and must finish before Percher can create the deploy checkpoint.` : "PocketBase is already creating a backup or restoring data for this app, so Percher could not create the deploy checkpoint yet.",
|
|
108795
|
+
suggestion: "Wait for the current backup, export or restore to finish, then publish again. If no operation is visible after a few minutes, contact support before retrying repeatedly."
|
|
108796
|
+
},
|
|
108797
|
+
CANARY_FAILED: {
|
|
108798
|
+
errorClass: "runtime_crash",
|
|
108799
|
+
phase: "start",
|
|
108800
|
+
cause: "canary_failed",
|
|
108801
|
+
title: "Your app went live, then failed its post-deploy check",
|
|
108802
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} The container started and passed its health check, so this is something that only shows up once the app is serving real requests.` : "Percher swapped your new version in, then its own public URL did not answer correctly. The container started and passed its health check, so this is something that only shows up once the app is serving real requests.",
|
|
108803
|
+
suggestion: "Run `percher doctor` — it re-probes the container and the public route and will say which half is failing. The container log from the moment it was rolled back is in the build log below. Retrying unchanged will usually fail the same way."
|
|
108804
|
+
},
|
|
108805
|
+
APP_DATA_MOUNT_CONFLICT: {
|
|
108806
|
+
errorClass: "app_data_mount_conflict",
|
|
108807
|
+
phase: "start",
|
|
108808
|
+
cause: "app_data_mount_conflict",
|
|
108809
|
+
title: "Your image has a file where Percher mounts /app/data",
|
|
108810
|
+
explanation: () => "The image built, but Docker could not start the container: every Percher app gets its persistent data volume mounted at /app/data, and this image has a file (or a link to one) at /app or /app/data, so that directory cannot be created.",
|
|
108811
|
+
suggestion: "Install the binary somewhere else, such as /usr/local/bin/app, and point ENTRYPOINT/CMD at it. If the project has a file named `data` at its root, rename it. Retrying unchanged will fail the same way."
|
|
108812
|
+
},
|
|
108813
|
+
WORKER_UNAVAILABLE: {
|
|
108814
|
+
errorClass: "infra_unavailable",
|
|
108815
|
+
phase: "infra",
|
|
108816
|
+
cause: "worker_fetch_failed",
|
|
108817
|
+
title: "Build worker is unreachable",
|
|
108818
|
+
explanation: (raw) => raw ? `The Percher build worker did not respond in time: ${trimMessage(raw)}. This is a platform-side issue, not your code.` : "The Percher build worker did not respond in time. This is a platform-side issue, not your code.",
|
|
108819
|
+
suggestion: "Wait 30 seconds and run `percher publish` again. If retry #2 also fails, pause 5 minutes before the next attempt — back-to-back retries during a partial outage just waste your time. After 3 spaced-out retries, check status.percher.app or contact support. Your build never started."
|
|
108820
|
+
},
|
|
108821
|
+
WORKER_UNAVAILABLE_PERSISTENT: {
|
|
108822
|
+
errorClass: "infra_unavailable",
|
|
108823
|
+
phase: "infra",
|
|
108824
|
+
cause: "worker_circuit_breaker_open",
|
|
108825
|
+
title: "Build worker is in a crash loop",
|
|
108826
|
+
explanation: () => "The Percher build worker has failed repeatedly in the last minute and the platform's circuit breaker has flipped open. Retrying immediately would just queue more failures.",
|
|
108827
|
+
suggestion: "Wait 2-3 minutes for the platform to recover, then retry. If it persists past 5 minutes check status.percher.app or contact support — this is a platform incident, not your code."
|
|
108828
|
+
},
|
|
108829
|
+
BUILD_TIMEOUT: {
|
|
108830
|
+
errorClass: "build_failed",
|
|
108831
|
+
phase: "build",
|
|
108832
|
+
cause: "build_timeout",
|
|
108833
|
+
title: "Build timed out",
|
|
108834
|
+
explanation: () => "The build ran longer than the 10-minute platform limit and was aborted.",
|
|
108835
|
+
suggestion: "Common causes: a slow `postinstall` hook, very large dependency tree, or a Dockerfile that pulls a huge base image. Try `bun install` locally and check what's slow. If it's legitimately a heavy build, contact support to discuss raising the limit for your account."
|
|
108836
|
+
},
|
|
108837
|
+
BUILD_FAILED: {
|
|
108838
|
+
errorClass: "build_failed",
|
|
108839
|
+
phase: "build",
|
|
108840
|
+
cause: "build_nonzero_exit",
|
|
108841
|
+
title: "Build failed",
|
|
108842
|
+
explanation: (raw) => raw ? `The build process returned a non-zero exit code: ${trimMessage(raw)}. Read the build log below for the exact error.` : "The build process returned a non-zero exit code. Read the build log below for the exact error.",
|
|
108843
|
+
suggestion: "Run your build locally to reproduce: `bun install && bun run build`. The error in the build log usually points to a missing dependency, a TypeScript/syntax error, or a misconfigured framework setting."
|
|
108844
|
+
},
|
|
108845
|
+
WORKER_ERROR: {
|
|
108846
|
+
errorClass: "infra_unavailable",
|
|
108847
|
+
phase: "infra",
|
|
108848
|
+
cause: "worker_internal_error",
|
|
108849
|
+
title: "Platform error inside the build worker",
|
|
108850
|
+
explanation: (raw) => raw ? `The build worker hit an internal error: ${trimMessage(raw)}. This is a Percher bug, not your code.` : "The build worker hit an internal error. This is a Percher bug, not your code.",
|
|
108851
|
+
suggestion: "Retry once — transient platform errors usually clear within a minute. If it repeats, please report it: include the deploy ID and we'll investigate. Your account is not at fault."
|
|
108852
|
+
},
|
|
108853
|
+
WORKER_ENDPOINT_MISSING: {
|
|
108854
|
+
errorClass: "infra_unavailable",
|
|
108855
|
+
phase: "infra",
|
|
108856
|
+
cause: "worker_endpoint_missing",
|
|
108857
|
+
title: "Platform worker is mid-upgrade",
|
|
108858
|
+
explanation: (raw) => raw ? `${trimMessage(raw)} The platform's worker process predates an endpoint this request needs — a rolling-deploy skew, not your code.` : "The platform's worker process predates an endpoint this request needs — a rolling-deploy skew, not your code.",
|
|
108859
|
+
suggestion: "Retry in a few minutes; the operator finishes the platform deploy worker-first. This failure does not count against your app."
|
|
108860
|
+
},
|
|
108861
|
+
DEPLOY_STALLED: {
|
|
108862
|
+
errorClass: "infra_unavailable",
|
|
108863
|
+
phase: "infra",
|
|
108864
|
+
cause: "deploy_stalled",
|
|
108865
|
+
title: "Deploy stalled",
|
|
108866
|
+
explanation: () => "The platform abandoned this deploy — likely because the API or build worker restarted mid-build. Your code is fine; the build never finished.",
|
|
108867
|
+
suggestion: "Run `percher publish` again. The new deploy will start fresh. If you see this repeatedly across multiple publishes, check status.percher.app — it implies a recurring platform issue."
|
|
108868
|
+
}
|
|
108869
|
+
};
|
|
108870
|
+
function classifyByErrorCode(code, rawMessage) {
|
|
108871
|
+
if (!code)
|
|
108872
|
+
return null;
|
|
108873
|
+
const mapping = MAPPINGS[code];
|
|
108874
|
+
if (!mapping)
|
|
108875
|
+
return null;
|
|
108876
|
+
return {
|
|
108877
|
+
title: mapping.title,
|
|
108878
|
+
explanation: mapping.explanation(rawMessage),
|
|
108879
|
+
suggestion: mapping.suggestion,
|
|
108880
|
+
errorClass: mapping.errorClass,
|
|
108881
|
+
phase: mapping.phase,
|
|
108882
|
+
cause: mapping.cause,
|
|
108883
|
+
relevantFiles: [],
|
|
108884
|
+
missingEnvVars: []
|
|
108885
|
+
};
|
|
108886
|
+
}
|
|
108887
|
+
function trimMessage(raw) {
|
|
108888
|
+
const firstLine = raw.split(`
|
|
108889
|
+
`)[0] ?? "";
|
|
108890
|
+
return firstLine.length > 200 ? `${firstLine.slice(0, 200)}…` : firstLine;
|
|
108891
|
+
}
|
|
108892
|
+
var PB_PROVISION_FAILED_ASK = {
|
|
108893
|
+
prompt: "The platform could not set up the database admin account. Publishing again after the platform failure is resolved is safe.",
|
|
108894
|
+
reasonCode: "pb_provision_failed",
|
|
108895
|
+
retryable: true
|
|
108896
|
+
};
|
|
108897
|
+
|
|
108462
108898
|
// ../core/dist/recovery.js
|
|
108463
108899
|
function recoveryNone(opts = {}) {
|
|
108464
108900
|
return {
|
|
@@ -108688,12 +109124,25 @@ function unprovenPlatformClaim(failure) {
|
|
|
108688
109124
|
}
|
|
108689
109125
|
function recoveryFromErrorClass(errorClass, failure) {
|
|
108690
109126
|
switch (errorClass) {
|
|
109127
|
+
case "build_secrets_unavailable":
|
|
109128
|
+
return recoveryAsk({
|
|
109129
|
+
prompt: "Percher cannot protect build secrets for this build. Should I remove the non-public keys from [build] pass_env and publish again, or wait and publish later?",
|
|
109130
|
+
options: [
|
|
109131
|
+
"remove non-public keys from [build] pass_env and publish again",
|
|
109132
|
+
"wait and publish later"
|
|
109133
|
+
],
|
|
109134
|
+
reasonCode: "build_secrets_unavailable"
|
|
109135
|
+
});
|
|
108691
109136
|
case "missing_env":
|
|
108692
109137
|
return recoveryEnv({
|
|
108693
109138
|
app: failure.appName,
|
|
108694
109139
|
keys: failure.missingEnvVars ?? [],
|
|
108695
109140
|
reasonCode: "missing_env"
|
|
108696
109141
|
});
|
|
109142
|
+
case "pb_provision_failed":
|
|
109143
|
+
if (failure.classSource !== "code")
|
|
109144
|
+
return unprovenPlatformClaim(failure);
|
|
109145
|
+
return recoveryAsk(PB_PROVISION_FAILED_ASK);
|
|
108697
109146
|
case "infra_unavailable":
|
|
108698
109147
|
if (failure.classSource !== "code")
|
|
108699
109148
|
return unprovenPlatformClaim(failure);
|
|
@@ -108784,9 +109233,280 @@ function recoveryFromErrorClass(errorClass, failure) {
|
|
|
108784
109233
|
}
|
|
108785
109234
|
}
|
|
108786
109235
|
|
|
109236
|
+
// ../core/dist/data-recovery.js
|
|
109237
|
+
var WRITES = new Set(["create", "update", "delete"]);
|
|
109238
|
+
function isDataRecordErrorCode(code) {
|
|
109239
|
+
return typeof code === "string" && Object.hasOwn(DATA_RECORD_ERROR_STATUS, code);
|
|
109240
|
+
}
|
|
109241
|
+
|
|
109242
|
+
class DataRecordError extends PercherApiError {
|
|
109243
|
+
target;
|
|
109244
|
+
constructor(err, target) {
|
|
109245
|
+
super(err.message, {
|
|
109246
|
+
status: err.status,
|
|
109247
|
+
code: err.code,
|
|
109248
|
+
requestId: err.requestId,
|
|
109249
|
+
extra: err.extra,
|
|
109250
|
+
cause: err
|
|
109251
|
+
});
|
|
109252
|
+
this.name = "DataRecordError";
|
|
109253
|
+
this.target = target;
|
|
109254
|
+
}
|
|
109255
|
+
}
|
|
109256
|
+
|
|
109257
|
+
// ../core/dist/commands/data-records.js
|
|
109258
|
+
var appArg = exports_external.string().min(1).optional().describe("App name or id. Defaults to the app in ./percher.toml.");
|
|
109259
|
+
var collectionArg = exports_external.string().regex(DATA_COLLECTION_RE, "a collection name: a letter, then letters, digits or _ (max 64)").describe("Collection name, exactly as percher_data_schema lists it (case-sensitive).");
|
|
109260
|
+
var recordIdArg = exports_external.string().regex(DATA_RECORD_ID_RE, "a record id: letters, digits, _ or - (max 64)").describe("Record id.");
|
|
109261
|
+
var expression = (what) => exports_external.string().max(DATA_LIMITS.expressionChars).optional().describe(what);
|
|
109262
|
+
var recordData = exports_external.record(exports_external.string(), exports_external.unknown()).describe("Field values keyed by field name (see percher_data_schema). File fields, hidden fields and unknown fields are refused.");
|
|
109263
|
+
var dataSchemaInputSchema = exports_external.object({ app: appArg });
|
|
109264
|
+
var dataQueryInputSchema = exports_external.object({
|
|
109265
|
+
app: appArg,
|
|
109266
|
+
collection: collectionArg,
|
|
109267
|
+
filter: expression("PocketBase-style filter over the collection's own fields, e.g. status = 'open' && priority >= 2. Operators = != > >= < <= ~ !~ and their ?-prefixed any-of forms; && || and parentheses. No @-variables, dotted paths, functions or backslashes."),
|
|
109268
|
+
sort: expression("Comma-separated fields, - for descending, e.g. -created,title (max 8)."),
|
|
109269
|
+
page: exports_external.number().int().min(1).max(DATA_LIMITS.maxPage).optional(),
|
|
109270
|
+
perPage: exports_external.number().int().min(1).max(DATA_LIMITS.maxPerPage).optional(),
|
|
109271
|
+
fields: expression("Comma-separated field names to return (default: every non-hidden field).")
|
|
109272
|
+
});
|
|
109273
|
+
var dataGetInputSchema = exports_external.object({
|
|
109274
|
+
app: appArg,
|
|
109275
|
+
collection: collectionArg,
|
|
109276
|
+
id: recordIdArg
|
|
109277
|
+
});
|
|
109278
|
+
var dataCreateInputSchema = exports_external.object({
|
|
109279
|
+
app: appArg,
|
|
109280
|
+
collection: collectionArg,
|
|
109281
|
+
data: recordData,
|
|
109282
|
+
id: recordIdArg.optional().describe("Optional id for the new record. With one, a create whose outcome is unknown can be checked with percher_data_get instead of searched for.")
|
|
109283
|
+
});
|
|
109284
|
+
var dataUpdateInputSchema = exports_external.object({
|
|
109285
|
+
app: appArg,
|
|
109286
|
+
collection: collectionArg,
|
|
109287
|
+
id: recordIdArg,
|
|
109288
|
+
data: recordData,
|
|
109289
|
+
ifUpdated: exports_external.string().min(1).max(64).optional().describe("The record's `updated` value as last read. The update is refused if it changed since. A best-effort timestamp check, not a lock: timestamp collisions and the app's own concurrent writes can defeat it.")
|
|
109290
|
+
});
|
|
109291
|
+
var dataDeleteInputSchema = exports_external.object({
|
|
109292
|
+
app: appArg,
|
|
109293
|
+
collection: collectionArg,
|
|
109294
|
+
id: recordIdArg
|
|
109295
|
+
});
|
|
109296
|
+
function resolveApp(ctx, app) {
|
|
109297
|
+
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
109298
|
+
if (!name) {
|
|
109299
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
109300
|
+
code: "data.no-app",
|
|
109301
|
+
hint: "Pass an app name or run from a directory with percher.toml."
|
|
109302
|
+
});
|
|
109303
|
+
}
|
|
109304
|
+
return name;
|
|
109305
|
+
}
|
|
109306
|
+
async function call(target, run) {
|
|
109307
|
+
try {
|
|
109308
|
+
return await run();
|
|
109309
|
+
} catch (err) {
|
|
109310
|
+
if (err instanceof PercherApiError && isDataRecordErrorCode(err.code)) {
|
|
109311
|
+
throw new DataRecordError(err, target);
|
|
109312
|
+
}
|
|
109313
|
+
throw err;
|
|
109314
|
+
}
|
|
109315
|
+
}
|
|
109316
|
+
function target(op, app, collection, id) {
|
|
109317
|
+
return {
|
|
109318
|
+
op,
|
|
109319
|
+
app,
|
|
109320
|
+
...collection !== undefined ? { collection } : {},
|
|
109321
|
+
...id !== undefined ? { id } : {}
|
|
109322
|
+
};
|
|
109323
|
+
}
|
|
109324
|
+
var SCHEMA_MAX_COLLECTIONS = DATA_LIMITS.schemaPerPage * DATA_LIMITS.schemaMaxPages;
|
|
109325
|
+
function omittedByRulesNote(omitted) {
|
|
109326
|
+
if (typeof omitted !== "number" || !Number.isSafeInteger(omitted) || omitted < 1 || omitted > SCHEMA_MAX_COLLECTIONS) {
|
|
109327
|
+
return;
|
|
109328
|
+
}
|
|
109329
|
+
const subject = omitted === 1 ? "1 collection in this app is" : `${omitted} collections in this app are`;
|
|
109330
|
+
return `${subject} reachable only with full access, which the app's own server code may use. The owner can choose full access for this app in Settings → Connections.`;
|
|
109331
|
+
}
|
|
109332
|
+
async function dataSchema2(ctx, input) {
|
|
109333
|
+
const app = resolveApp(ctx, input.app);
|
|
109334
|
+
const schema = await call(target("schema", app), () => ctx.client.data.getSchema(app));
|
|
109335
|
+
const { note: _fromApi, ...rest } = schema;
|
|
109336
|
+
const note = omittedByRulesNote(rest.omittedByRules);
|
|
109337
|
+
return note === undefined ? rest : { ...rest, note };
|
|
109338
|
+
}
|
|
109339
|
+
async function dataQuery(ctx, input) {
|
|
109340
|
+
const { app: rawApp, collection, ...query } = input;
|
|
109341
|
+
const app = resolveApp(ctx, rawApp);
|
|
109342
|
+
return call(target("query", app, collection), () => ctx.client.data.queryRecords(app, collection, query));
|
|
109343
|
+
}
|
|
109344
|
+
async function dataGet(ctx, input) {
|
|
109345
|
+
const app = resolveApp(ctx, input.app);
|
|
109346
|
+
return call(target("get", app, input.collection, input.id), () => ctx.client.data.getRecord(app, input.collection, input.id));
|
|
109347
|
+
}
|
|
109348
|
+
async function dataCreate(ctx, input) {
|
|
109349
|
+
const app = resolveApp(ctx, input.app);
|
|
109350
|
+
const body = {
|
|
109351
|
+
data: input.data,
|
|
109352
|
+
...input.id !== undefined ? { id: input.id } : {}
|
|
109353
|
+
};
|
|
109354
|
+
return call(target("create", app, input.collection, input.id), () => ctx.client.data.createRecord(app, input.collection, body));
|
|
109355
|
+
}
|
|
109356
|
+
async function dataUpdate(ctx, input) {
|
|
109357
|
+
const app = resolveApp(ctx, input.app);
|
|
109358
|
+
const body = {
|
|
109359
|
+
data: input.data,
|
|
109360
|
+
...input.ifUpdated !== undefined ? { ifUpdated: input.ifUpdated } : {}
|
|
109361
|
+
};
|
|
109362
|
+
return call(target("update", app, input.collection, input.id), () => ctx.client.data.updateRecord(app, input.collection, input.id, body));
|
|
109363
|
+
}
|
|
109364
|
+
async function dataDelete(ctx, input) {
|
|
109365
|
+
const app = resolveApp(ctx, input.app);
|
|
109366
|
+
await call(target("delete", app, input.collection, input.id), () => ctx.client.data.deleteRecord(app, input.collection, input.id));
|
|
109367
|
+
return { deleted: true, collection: input.collection, id: input.id };
|
|
109368
|
+
}
|
|
109369
|
+
// ../core/dist/commands/delete.js
|
|
109370
|
+
var deleteInputSchema = exports_external.object({
|
|
109371
|
+
app: exports_external.string().optional().describe("App name to delete (defaults to percher.toml app name)"),
|
|
109372
|
+
confirm: exports_external.boolean().describe("Must be true to confirm deletion. This is a destructive operation that permanently removes the app, its container, database, domains, env vars, and deploy history.")
|
|
109373
|
+
});
|
|
109374
|
+
async function deleteApp(ctx, input) {
|
|
109375
|
+
const name = input.app ?? readPercherTomlAppName(ctx.cwd);
|
|
109376
|
+
if (!name) {
|
|
109377
|
+
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
109378
|
+
code: "env.no-app",
|
|
109379
|
+
hint: "Pass an app name or run from a directory with percher.toml."
|
|
109380
|
+
});
|
|
109381
|
+
}
|
|
109382
|
+
if (!input.confirm) {
|
|
109383
|
+
throw new PercherCoreError(`Deletion requires explicit confirmation. Set confirm: true to delete "${name}" permanently.`, {
|
|
109384
|
+
code: "delete.confirmation-required",
|
|
109385
|
+
hint: `This will permanently delete the app "${name}" and all its data. Pass confirm: true to proceed.`
|
|
109386
|
+
});
|
|
109387
|
+
}
|
|
109388
|
+
await ctx.client.apps.delete(name);
|
|
109389
|
+
}
|
|
109390
|
+
// ../core/dist/commands/deploy-repo.js
|
|
109391
|
+
init_dist();
|
|
109392
|
+
|
|
109393
|
+
// ../core/dist/deployment-replaced.js
|
|
109394
|
+
var summary = "This deployment is no longer active. Inspect the app's current state before deploying again.";
|
|
109395
|
+
function recovery(app, deployId) {
|
|
109396
|
+
return recoveryDoctor({ app, deployId, mode: "deploy", reasonCode: "replaced_by_newer" });
|
|
109397
|
+
}
|
|
109398
|
+
function throwIfDeploymentReplaced(app, deployment) {
|
|
109399
|
+
if (deployment.status !== "replaced")
|
|
109400
|
+
return;
|
|
109401
|
+
throw new PercherCoreError(summary, {
|
|
109402
|
+
code: "push.deploy-replaced",
|
|
109403
|
+
hint: `Run \`percher doctor --app ${app}\` to inspect the current state.`,
|
|
109404
|
+
recovery: { ...recovery(app, deployment.id) }
|
|
109405
|
+
});
|
|
109406
|
+
}
|
|
109407
|
+
function replacedDeploymentResult(app, deployment) {
|
|
109408
|
+
return {
|
|
109409
|
+
status: "replaced",
|
|
109410
|
+
app,
|
|
109411
|
+
deployment,
|
|
109412
|
+
summary,
|
|
109413
|
+
recovery: recovery(app.name, deployment.id),
|
|
109414
|
+
fileCount: 0,
|
|
109415
|
+
bytes: 0,
|
|
109416
|
+
configPath: "",
|
|
109417
|
+
bundle: { fileCount: 0, bytes: 0 }
|
|
109418
|
+
};
|
|
109419
|
+
}
|
|
109420
|
+
|
|
109421
|
+
// ../core/dist/poll-deployment.js
|
|
109422
|
+
init_dist();
|
|
109423
|
+
class DeployPollLostContactError extends PercherCoreError {
|
|
109424
|
+
deploymentId;
|
|
109425
|
+
constructor(message, deploymentId, appName, options) {
|
|
109426
|
+
super(message, {
|
|
109427
|
+
code: "push.lost-contact",
|
|
109428
|
+
hint: `The deploy may already be live. Check with: percher deploys ${appName}`,
|
|
109429
|
+
cause: options?.cause
|
|
109430
|
+
});
|
|
109431
|
+
this.deploymentId = deploymentId;
|
|
109432
|
+
this.name = "DeployPollLostContactError";
|
|
109433
|
+
}
|
|
109434
|
+
}
|
|
109435
|
+
function isTransientPollError(err) {
|
|
109436
|
+
if (isTransientNetworkError(err))
|
|
109437
|
+
return true;
|
|
109438
|
+
if (err instanceof PercherApiError)
|
|
109439
|
+
return err.status === 429 || err.status === 502 || err.status === 503 || err.status === 504;
|
|
109440
|
+
return err instanceof TypeError && /terminated/i.test(err.message);
|
|
109441
|
+
}
|
|
109442
|
+
async function pollDeployment(opts) {
|
|
109443
|
+
const terminal = opts.terminal ?? ["live", "failed", "replaced"];
|
|
109444
|
+
const intervalMs = opts.intervalMs ?? 2000;
|
|
109445
|
+
const timeoutMs = opts.timeoutMs ?? TIMEOUTS.clientPublishPoll;
|
|
109446
|
+
const maxRetries = opts.maxRetries ?? Number.POSITIVE_INFINITY;
|
|
109447
|
+
const retryBudgetMs = opts.retryBudgetMs ?? 5 * 60000;
|
|
109448
|
+
let deployment = opts.initial;
|
|
109449
|
+
const startedAt = Date.now();
|
|
109450
|
+
const seenEventIds = new Set;
|
|
109451
|
+
if (opts.onEvent) {
|
|
109452
|
+
await drainNewEvents(opts, deployment.id, seenEventIds);
|
|
109453
|
+
}
|
|
109454
|
+
while (!terminal.includes(deployment.status)) {
|
|
109455
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
109456
|
+
opts.onTimeout(deployment);
|
|
109457
|
+
}
|
|
109458
|
+
opts.onTick?.(deployment);
|
|
109459
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
109460
|
+
let attempt = 0;
|
|
109461
|
+
let streakStartedAt = 0;
|
|
109462
|
+
let polled = false;
|
|
109463
|
+
while (!polled) {
|
|
109464
|
+
try {
|
|
109465
|
+
deployment = await opts.ctx.client.apps.getDeployment(opts.appId, deployment.id);
|
|
109466
|
+
polled = true;
|
|
109467
|
+
} catch (err) {
|
|
109468
|
+
attempt++;
|
|
109469
|
+
if (!isTransientPollError(err))
|
|
109470
|
+
throw err;
|
|
109471
|
+
if (attempt === 1) {
|
|
109472
|
+
streakStartedAt = Date.now();
|
|
109473
|
+
opts.ctx.status(err instanceof PercherApiError && err.status === 429 ? "Percher asked this client to slow down; retrying while the deploy continues..." : "Lost contact with Percher; retrying while the deploy continues...");
|
|
109474
|
+
}
|
|
109475
|
+
if (Date.now() - startedAt > timeoutMs)
|
|
109476
|
+
opts.onTimeout(deployment);
|
|
109477
|
+
if (attempt >= maxRetries || Date.now() - streakStartedAt >= retryBudgetMs) {
|
|
109478
|
+
const msg = err.message ?? String(err);
|
|
109479
|
+
throw new DeployPollLostContactError(`${msg}
|
|
109480
|
+
|
|
109481
|
+
The deploy may already be live — contact with Percher was lost mid-poll. Check with: percher deploys ${opts.appName}`, deployment.id, opts.appName, { cause: err });
|
|
109482
|
+
}
|
|
109483
|
+
const backoff = (opts.backoffMs ?? ((n) => Math.min(1000 * 2 ** (n - 1), 15000)))(attempt);
|
|
109484
|
+
await new Promise((r) => setTimeout(r, backoff));
|
|
109485
|
+
}
|
|
109486
|
+
}
|
|
109487
|
+
if (opts.onEvent) {
|
|
109488
|
+
await drainNewEvents(opts, deployment.id, seenEventIds);
|
|
109489
|
+
}
|
|
109490
|
+
}
|
|
109491
|
+
return deployment;
|
|
109492
|
+
}
|
|
109493
|
+
async function drainNewEvents(opts, deployId, seenEventIds) {
|
|
109494
|
+
if (!opts.onEvent)
|
|
109495
|
+
return;
|
|
109496
|
+
try {
|
|
109497
|
+
const { events } = await opts.ctx.client.apps.getDeployEvents(opts.appId, deployId);
|
|
109498
|
+
for (const event of events) {
|
|
109499
|
+
if (seenEventIds.has(event.id))
|
|
109500
|
+
continue;
|
|
109501
|
+
seenEventIds.add(event.id);
|
|
109502
|
+
opts.onEvent(event);
|
|
109503
|
+
}
|
|
109504
|
+
} catch {}
|
|
109505
|
+
}
|
|
109506
|
+
|
|
108787
109507
|
// ../core/dist/commands/publish-failure.js
|
|
108788
109508
|
init_dist();
|
|
108789
|
-
import { join as
|
|
109509
|
+
import { join as join10 } from "node:path";
|
|
108790
109510
|
|
|
108791
109511
|
// ../core/dist/error-classifier.js
|
|
108792
109512
|
function extractEnvVarsFromLog(combined) {
|
|
@@ -108804,6 +109524,19 @@ function extractModuleFromLog(combined) {
|
|
|
108804
109524
|
return match?.[1];
|
|
108805
109525
|
}
|
|
108806
109526
|
var patterns = [
|
|
109527
|
+
{
|
|
109528
|
+
pattern: /PB_PROVISION_FAILED|the platform could not set up the database admin account/i,
|
|
109529
|
+
result: {
|
|
109530
|
+
title: "Database admin setup failed",
|
|
109531
|
+
explanation: "The platform could not set up the database admin account.",
|
|
109532
|
+
suggestion: "Publishing again after the platform failure is resolved is safe.",
|
|
109533
|
+
errorClass: "pb_provision_failed",
|
|
109534
|
+
phase: "infra",
|
|
109535
|
+
cause: "pb_provision_failed",
|
|
109536
|
+
relevantFiles: [],
|
|
109537
|
+
missingEnvVars: []
|
|
109538
|
+
}
|
|
109539
|
+
},
|
|
108807
109540
|
{
|
|
108808
109541
|
pattern: /DEPLOY_STALLED:/,
|
|
108809
109542
|
result: {
|
|
@@ -109172,171 +109905,9 @@ ${buildLog ?? ""}`;
|
|
|
109172
109905
|
return null;
|
|
109173
109906
|
}
|
|
109174
109907
|
|
|
109175
|
-
// ../core/dist/structured-error-codes.js
|
|
109176
|
-
var MAPPINGS = {
|
|
109177
|
-
PLATFORM_DISK_LOW: {
|
|
109178
|
-
errorClass: "platform_at_capacity",
|
|
109179
|
-
phase: "infra",
|
|
109180
|
-
cause: "disk_headroom_exhausted",
|
|
109181
|
-
title: "Platform storage is too low",
|
|
109182
|
-
explanation: () => "Percher paused new deploys: the platform is nearly out of disk. Not your app — nothing to change. Deployed apps keep running; only new deploys are paused.",
|
|
109183
|
-
suggestion: "The operator is alerted automatically. Run `percher publish` again in ~15 min; this failure does not count against your app. Still failing after an hour: https://percher.app/status"
|
|
109184
|
-
},
|
|
109185
|
-
PLATFORM_DISK_UNKNOWN: {
|
|
109186
|
-
errorClass: "platform_at_capacity",
|
|
109187
|
-
phase: "infra",
|
|
109188
|
-
cause: "disk_state_unreadable",
|
|
109189
|
-
title: "Platform storage state is unknown",
|
|
109190
|
-
explanation: () => "Percher paused new deploys: it can't read how much disk is left, and won't assume there's room. Not your app. Deployed apps have not been stopped by this.",
|
|
109191
|
-
suggestion: "Run `percher publish` again in ~5 min; this failure does not count against your app. Still failing after 15 min: https://percher.app/status"
|
|
109192
|
-
},
|
|
109193
|
-
PLAN_POOL_EXCEEDED: {
|
|
109194
|
-
errorClass: "plan_pool_exceeded",
|
|
109195
|
-
phase: "start",
|
|
109196
|
-
cause: "plan_pool_exceeded",
|
|
109197
|
-
title: "Plan resource pool is full",
|
|
109198
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} The platform is fine — the account is at its plan's limit.` : "This deploy would commit more RAM, vCPU or disk than your plan's pool allows across all your apps. The platform is fine — the account is at its limit.",
|
|
109199
|
-
suggestion: "Reduce `[resources]` in this app's percher.toml, delete an app you no longer need, or upgrade at https://percher.app/account/billing. Retrying unchanged will fail the same way."
|
|
109200
|
-
},
|
|
109201
|
-
PLACEMENT_UNDETERMINED: {
|
|
109202
|
-
errorClass: "infra_unavailable",
|
|
109203
|
-
phase: "infra",
|
|
109204
|
-
cause: "placement_undetermined",
|
|
109205
|
-
title: "Percher could not place your app's container",
|
|
109206
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} This is a platform-side read of Percher's own container placement, not anything in your app.` : "Percher could not read which internal network this app's current containers are on, and refused to guess rather than risk splitting the app from its database across two networks.",
|
|
109207
|
-
suggestion: "Nothing to change in your app. Retry in a minute; if it persists, the platform is having trouble reaching its container daemon and Percher's operators are alerted."
|
|
109208
|
-
},
|
|
109209
|
-
PLATFORM_MEMORY_LOW: {
|
|
109210
|
-
errorClass: "platform_at_capacity",
|
|
109211
|
-
phase: "infra",
|
|
109212
|
-
cause: "box_admission_rejected",
|
|
109213
|
-
title: "Platform is at capacity",
|
|
109214
|
-
explanation: (raw) => raw ? `Percher couldn't fit this deploy on the box right now: ${trimMessage(raw)} Not your app — nothing to change. Deployed apps keep running.` : "Percher couldn't fit this deploy on the box right now — the admission gate refused to start the container. Not your app — nothing to change. Deployed apps keep running.",
|
|
109215
|
-
suggestion: "Run `percher publish` again in a few minutes; capacity frees up as other deploys finish, and this failure does not count against your app. Still failing after an hour: https://percher.app/status"
|
|
109216
|
-
},
|
|
109217
|
-
PB_BRIDGE_UNAVAILABLE: {
|
|
109218
|
-
errorClass: "infra_unavailable",
|
|
109219
|
-
phase: "infra",
|
|
109220
|
-
cause: "pb_bridge_unreachable",
|
|
109221
|
-
title: "PocketBase is unreachable from the platform",
|
|
109222
|
-
explanation: (raw) => raw ? `Percher could not reach your app's database through its internal bridge: ${trimMessage(raw)}. This is a platform-side issue — your data and your code are both fine.` : "Percher could not reach your app's database through its internal bridge. This is a platform-side issue — your data and your code are both fine.",
|
|
109223
|
-
suggestion: "Wait a minute and run `percher publish` again; this failure does not count against your app. Your data was not touched — the platform could not read it, which is not the same as it being missing. Still failing after 15 min: https://percher.app/status"
|
|
109224
|
-
},
|
|
109225
|
-
PB_ROTATION_UNVERIFIED: {
|
|
109226
|
-
errorClass: "infra_unavailable",
|
|
109227
|
-
phase: "infra",
|
|
109228
|
-
cause: "pb_rotation_unverified",
|
|
109229
|
-
title: "PocketBase admin password was rotated but not confirmed",
|
|
109230
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} The rotation itself ran, so the previously stored admin password may now be stale. Your app data was not modified — only the admin credential changed.` : "Percher rotated your app's PocketBase admin password, then could not confirm the rotation. The previously stored admin password may now be stale. Your app data was not modified — only the admin credential changed.",
|
|
109231
|
-
suggestion: "Run the superuser reset again (`percher data reset-superuser` or the dashboard's reset button) — the rotation is idempotent, and a successful re-run stores a fresh working credential. This failure does not count against your app."
|
|
109232
|
-
},
|
|
109233
|
-
PB_OPERATION_BUSY: {
|
|
109234
|
-
errorClass: "pb_operation_busy",
|
|
109235
|
-
phase: "start",
|
|
109236
|
-
cause: "pb_backup_restore_busy",
|
|
109237
|
-
title: "PocketBase is finishing another data operation",
|
|
109238
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} The operation is scoped to this app and must finish before Percher can create the deploy checkpoint.` : "PocketBase is already creating a backup or restoring data for this app, so Percher could not create the deploy checkpoint yet.",
|
|
109239
|
-
suggestion: "Wait for the current backup, export or restore to finish, then publish again. If no operation is visible after a few minutes, contact support before retrying repeatedly."
|
|
109240
|
-
},
|
|
109241
|
-
CANARY_FAILED: {
|
|
109242
|
-
errorClass: "runtime_crash",
|
|
109243
|
-
phase: "start",
|
|
109244
|
-
cause: "canary_failed",
|
|
109245
|
-
title: "Your app went live, then failed its post-deploy check",
|
|
109246
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} The container started and passed its health check, so this is something that only shows up once the app is serving real requests.` : "Percher swapped your new version in, then its own public URL did not answer correctly. The container started and passed its health check, so this is something that only shows up once the app is serving real requests.",
|
|
109247
|
-
suggestion: "Run `percher doctor` — it re-probes the container and the public route and will say which half is failing. The container log from the moment it was rolled back is in the build log below. Retrying unchanged will usually fail the same way."
|
|
109248
|
-
},
|
|
109249
|
-
APP_DATA_MOUNT_CONFLICT: {
|
|
109250
|
-
errorClass: "app_data_mount_conflict",
|
|
109251
|
-
phase: "start",
|
|
109252
|
-
cause: "app_data_mount_conflict",
|
|
109253
|
-
title: "Your image has a file where Percher mounts /app/data",
|
|
109254
|
-
explanation: () => "The image built, but Docker could not start the container: every Percher app gets its persistent data volume mounted at /app/data, and this image has a file (or a link to one) at /app or /app/data, so that directory cannot be created.",
|
|
109255
|
-
suggestion: "Install the binary somewhere else, such as /usr/local/bin/app, and point ENTRYPOINT/CMD at it. If the project has a file named `data` at its root, rename it. Retrying unchanged will fail the same way."
|
|
109256
|
-
},
|
|
109257
|
-
WORKER_UNAVAILABLE: {
|
|
109258
|
-
errorClass: "infra_unavailable",
|
|
109259
|
-
phase: "infra",
|
|
109260
|
-
cause: "worker_fetch_failed",
|
|
109261
|
-
title: "Build worker is unreachable",
|
|
109262
|
-
explanation: (raw) => raw ? `The Percher build worker did not respond in time: ${trimMessage(raw)}. This is a platform-side issue, not your code.` : "The Percher build worker did not respond in time. This is a platform-side issue, not your code.",
|
|
109263
|
-
suggestion: "Wait 30 seconds and run `percher publish` again. If retry #2 also fails, pause 5 minutes before the next attempt — back-to-back retries during a partial outage just waste your time. After 3 spaced-out retries, check status.percher.app or contact support. Your build never started."
|
|
109264
|
-
},
|
|
109265
|
-
WORKER_UNAVAILABLE_PERSISTENT: {
|
|
109266
|
-
errorClass: "infra_unavailable",
|
|
109267
|
-
phase: "infra",
|
|
109268
|
-
cause: "worker_circuit_breaker_open",
|
|
109269
|
-
title: "Build worker is in a crash loop",
|
|
109270
|
-
explanation: () => "The Percher build worker has failed repeatedly in the last minute and the platform's circuit breaker has flipped open. Retrying immediately would just queue more failures.",
|
|
109271
|
-
suggestion: "Wait 2-3 minutes for the platform to recover, then retry. If it persists past 5 minutes check status.percher.app or contact support — this is a platform incident, not your code."
|
|
109272
|
-
},
|
|
109273
|
-
BUILD_TIMEOUT: {
|
|
109274
|
-
errorClass: "build_failed",
|
|
109275
|
-
phase: "build",
|
|
109276
|
-
cause: "build_timeout",
|
|
109277
|
-
title: "Build timed out",
|
|
109278
|
-
explanation: () => "The build ran longer than the 10-minute platform limit and was aborted.",
|
|
109279
|
-
suggestion: "Common causes: a slow `postinstall` hook, very large dependency tree, or a Dockerfile that pulls a huge base image. Try `bun install` locally and check what's slow. If it's legitimately a heavy build, contact support to discuss raising the limit for your account."
|
|
109280
|
-
},
|
|
109281
|
-
BUILD_FAILED: {
|
|
109282
|
-
errorClass: "build_failed",
|
|
109283
|
-
phase: "build",
|
|
109284
|
-
cause: "build_nonzero_exit",
|
|
109285
|
-
title: "Build failed",
|
|
109286
|
-
explanation: (raw) => raw ? `The build process returned a non-zero exit code: ${trimMessage(raw)}. Read the build log below for the exact error.` : "The build process returned a non-zero exit code. Read the build log below for the exact error.",
|
|
109287
|
-
suggestion: "Run your build locally to reproduce: `bun install && bun run build`. The error in the build log usually points to a missing dependency, a TypeScript/syntax error, or a misconfigured framework setting."
|
|
109288
|
-
},
|
|
109289
|
-
WORKER_ERROR: {
|
|
109290
|
-
errorClass: "infra_unavailable",
|
|
109291
|
-
phase: "infra",
|
|
109292
|
-
cause: "worker_internal_error",
|
|
109293
|
-
title: "Platform error inside the build worker",
|
|
109294
|
-
explanation: (raw) => raw ? `The build worker hit an internal error: ${trimMessage(raw)}. This is a Percher bug, not your code.` : "The build worker hit an internal error. This is a Percher bug, not your code.",
|
|
109295
|
-
suggestion: "Retry once — transient platform errors usually clear within a minute. If it repeats, please report it: include the deploy ID and we'll investigate. Your account is not at fault."
|
|
109296
|
-
},
|
|
109297
|
-
WORKER_ENDPOINT_MISSING: {
|
|
109298
|
-
errorClass: "infra_unavailable",
|
|
109299
|
-
phase: "infra",
|
|
109300
|
-
cause: "worker_endpoint_missing",
|
|
109301
|
-
title: "Platform worker is mid-upgrade",
|
|
109302
|
-
explanation: (raw) => raw ? `${trimMessage(raw)} The platform's worker process predates an endpoint this request needs — a rolling-deploy skew, not your code.` : "The platform's worker process predates an endpoint this request needs — a rolling-deploy skew, not your code.",
|
|
109303
|
-
suggestion: "Retry in a few minutes; the operator finishes the platform deploy worker-first. This failure does not count against your app."
|
|
109304
|
-
},
|
|
109305
|
-
DEPLOY_STALLED: {
|
|
109306
|
-
errorClass: "infra_unavailable",
|
|
109307
|
-
phase: "infra",
|
|
109308
|
-
cause: "deploy_stalled",
|
|
109309
|
-
title: "Deploy stalled",
|
|
109310
|
-
explanation: () => "The platform abandoned this deploy — likely because the API or build worker restarted mid-build. Your code is fine; the build never finished.",
|
|
109311
|
-
suggestion: "Run `percher publish` again. The new deploy will start fresh. If you see this repeatedly across multiple publishes, check status.percher.app — it implies a recurring platform issue."
|
|
109312
|
-
}
|
|
109313
|
-
};
|
|
109314
|
-
function classifyByErrorCode(code, rawMessage) {
|
|
109315
|
-
if (!code)
|
|
109316
|
-
return null;
|
|
109317
|
-
const mapping = MAPPINGS[code];
|
|
109318
|
-
if (!mapping)
|
|
109319
|
-
return null;
|
|
109320
|
-
return {
|
|
109321
|
-
title: mapping.title,
|
|
109322
|
-
explanation: mapping.explanation(rawMessage),
|
|
109323
|
-
suggestion: mapping.suggestion,
|
|
109324
|
-
errorClass: mapping.errorClass,
|
|
109325
|
-
phase: mapping.phase,
|
|
109326
|
-
cause: mapping.cause,
|
|
109327
|
-
relevantFiles: [],
|
|
109328
|
-
missingEnvVars: []
|
|
109329
|
-
};
|
|
109330
|
-
}
|
|
109331
|
-
function trimMessage(raw) {
|
|
109332
|
-
const firstLine = raw.split(`
|
|
109333
|
-
`)[0] ?? "";
|
|
109334
|
-
return firstLine.length > 200 ? `${firstLine.slice(0, 200)}…` : firstLine;
|
|
109335
|
-
}
|
|
109336
|
-
|
|
109337
109908
|
// ../core/dist/commands/publish-failure.js
|
|
109338
109909
|
function tomlPathFor(cwd) {
|
|
109339
|
-
return
|
|
109910
|
+
return join10(cwd, "percher.toml");
|
|
109340
109911
|
}
|
|
109341
109912
|
async function buildFailureError(ctx, app, deployment, signal) {
|
|
109342
109913
|
let buildLogTail;
|
|
@@ -109408,7 +109979,7 @@ async function classifyDeploymentFailure(opts) {
|
|
|
109408
109979
|
error48.suggestion = `${error48.suggestion}
|
|
109409
109980
|
To return to the last version that ran cleanly: \`bunx percher rollback --last-good\`.`;
|
|
109410
109981
|
}
|
|
109411
|
-
const
|
|
109982
|
+
const recovery2 = error48.errorClass ? recoveryFromErrorClass(error48.errorClass, {
|
|
109412
109983
|
missingEnvVars: error48.missingEnvVars,
|
|
109413
109984
|
deployId: deployment.id,
|
|
109414
109985
|
appName: app.name,
|
|
@@ -109422,13 +109993,13 @@ To return to the last version that ran cleanly: \`bunx percher rollback --last-g
|
|
|
109422
109993
|
});
|
|
109423
109994
|
return {
|
|
109424
109995
|
error: error48,
|
|
109425
|
-
recovery,
|
|
109996
|
+
recovery: recovery2,
|
|
109426
109997
|
summary: `${error48.title} (${app.name}, deploy ${deployment.id}).`
|
|
109427
109998
|
};
|
|
109428
109999
|
}
|
|
109429
110000
|
async function buildFailureResult(opts) {
|
|
109430
110001
|
const { ctx, app, deployment, tarball, input } = opts;
|
|
109431
|
-
const { error: error48, recovery, summary } = await classifyDeploymentFailure({
|
|
110002
|
+
const { error: error48, recovery: recovery2, summary: summary2 } = await classifyDeploymentFailure({
|
|
109432
110003
|
ctx,
|
|
109433
110004
|
app,
|
|
109434
110005
|
deployment,
|
|
@@ -109441,8 +110012,8 @@ async function buildFailureResult(opts) {
|
|
|
109441
110012
|
fileCount: tarball.fileCount,
|
|
109442
110013
|
bytes: tarball.bytes,
|
|
109443
110014
|
error: error48,
|
|
109444
|
-
recovery,
|
|
109445
|
-
summary,
|
|
110015
|
+
recovery: recovery2,
|
|
110016
|
+
summary: summary2,
|
|
109446
110017
|
configPath: tomlPathFor(ctx.cwd),
|
|
109447
110018
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
109448
110019
|
};
|
|
@@ -109521,13 +110092,13 @@ async function deploysInspect(ctx, input) {
|
|
|
109521
110092
|
}
|
|
109522
110093
|
// ../core/dist/commands/dev.js
|
|
109523
110094
|
import { existsSync as existsSync8 } from "node:fs";
|
|
109524
|
-
import { join as
|
|
110095
|
+
import { join as join13 } from "node:path";
|
|
109525
110096
|
|
|
109526
110097
|
// ../core/dist/tarball.js
|
|
109527
110098
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
109528
110099
|
import { createHash as createHash2 } from "node:crypto";
|
|
109529
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as
|
|
109530
|
-
import { join as
|
|
110100
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
|
|
110101
|
+
import { join as join11, relative as relative4, sep as sep2 } from "node:path";
|
|
109531
110102
|
import { Readable } from "node:stream";
|
|
109532
110103
|
import { createGzip } from "node:zlib";
|
|
109533
110104
|
function isFilesOptions(options) {
|
|
@@ -109551,7 +110122,7 @@ var ALWAYS_IGNORE_SECRETS = [".env", ".env.*"];
|
|
|
109551
110122
|
function* walk(dir, baseDir, ig) {
|
|
109552
110123
|
const entries = readdirSync2(dir);
|
|
109553
110124
|
for (const name of entries) {
|
|
109554
|
-
const full =
|
|
110125
|
+
const full = join11(dir, name);
|
|
109555
110126
|
const rel = relative4(baseDir, full).split(sep2).join("/");
|
|
109556
110127
|
if (ig.ignores(rel))
|
|
109557
110128
|
continue;
|
|
@@ -109640,20 +110211,20 @@ async function createTarball(options) {
|
|
|
109640
110211
|
}
|
|
109641
110212
|
const ig = import_ignore.default();
|
|
109642
110213
|
ig.add(DEFAULT_IGNORE);
|
|
109643
|
-
const gitignorePath =
|
|
110214
|
+
const gitignorePath = join11(options.cwd, ".gitignore");
|
|
109644
110215
|
if (existsSync6(gitignorePath)) {
|
|
109645
|
-
ig.add(
|
|
110216
|
+
ig.add(readFileSync7(gitignorePath, "utf8"));
|
|
109646
110217
|
}
|
|
109647
|
-
const percherignorePath =
|
|
110218
|
+
const percherignorePath = join11(options.cwd, ".percherignore");
|
|
109648
110219
|
if (existsSync6(percherignorePath)) {
|
|
109649
|
-
ig.add(
|
|
110220
|
+
ig.add(readFileSync7(percherignorePath, "utf8"));
|
|
109650
110221
|
}
|
|
109651
110222
|
if (options.extraIgnore)
|
|
109652
110223
|
ig.add(options.extraIgnore);
|
|
109653
110224
|
ig.add(ALWAYS_IGNORE_SECRETS);
|
|
109654
110225
|
const fileBuffers = [];
|
|
109655
110226
|
for (const rel of walk(options.cwd, options.cwd, ig)) {
|
|
109656
|
-
const data2 =
|
|
110227
|
+
const data2 = readFileSync7(join11(options.cwd, rel));
|
|
109657
110228
|
fileBuffers.push({ path: rel, size: data2.length, data: data2 });
|
|
109658
110229
|
}
|
|
109659
110230
|
return buildTarball(fileBuffers);
|
|
@@ -109675,8 +110246,8 @@ function createTarballFromFiles(files, _config) {
|
|
|
109675
110246
|
|
|
109676
110247
|
// ../core/dist/watcher.js
|
|
109677
110248
|
var import_ignore2 = __toESM(require_ignore(), 1);
|
|
109678
|
-
import { existsSync as existsSync7, readFileSync as
|
|
109679
|
-
import { join as
|
|
110249
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8, watch } from "node:fs";
|
|
110250
|
+
import { join as join12, sep as sep3 } from "node:path";
|
|
109680
110251
|
var DEFAULT_IGNORE2 = [
|
|
109681
110252
|
"node_modules",
|
|
109682
110253
|
".git",
|
|
@@ -109696,9 +110267,9 @@ function createWatcher(options) {
|
|
|
109696
110267
|
const debounceMs = options.debounceMs ?? 500;
|
|
109697
110268
|
const ig = import_ignore2.default();
|
|
109698
110269
|
ig.add(DEFAULT_IGNORE2);
|
|
109699
|
-
const gitignorePath =
|
|
110270
|
+
const gitignorePath = join12(options.cwd, ".gitignore");
|
|
109700
110271
|
if (existsSync7(gitignorePath)) {
|
|
109701
|
-
ig.add(
|
|
110272
|
+
ig.add(readFileSync8(gitignorePath, "utf8"));
|
|
109702
110273
|
}
|
|
109703
110274
|
if (options.extraIgnore)
|
|
109704
110275
|
ig.add(options.extraIgnore);
|
|
@@ -109736,7 +110307,7 @@ var devInputSchema = exports_external.object({
|
|
|
109736
110307
|
app: exports_external.string().optional()
|
|
109737
110308
|
});
|
|
109738
110309
|
async function loadConfig2(ctx, appOverride) {
|
|
109739
|
-
const tomlPath =
|
|
110310
|
+
const tomlPath = join13(ctx.cwd, "percher.toml");
|
|
109740
110311
|
if (!existsSync8(tomlPath)) {
|
|
109741
110312
|
throw new PercherCoreError("No percher.toml found. Run: percher init", {
|
|
109742
110313
|
code: "dev.no-app",
|
|
@@ -109932,7 +110503,7 @@ async function diff(ctx, input = {}) {
|
|
|
109932
110503
|
}
|
|
109933
110504
|
// ../core/dist/commands/doctor.js
|
|
109934
110505
|
import { existsSync as existsSync9 } from "node:fs";
|
|
109935
|
-
import { join as
|
|
110506
|
+
import { join as join14 } from "node:path";
|
|
109936
110507
|
|
|
109937
110508
|
// ../core/dist/toml-recovery.js
|
|
109938
110509
|
function tomlErrorToRecoveryProblems(err) {
|
|
@@ -110018,7 +110589,7 @@ async function waitForDeploy(ctx, input, opts) {
|
|
|
110018
110589
|
}
|
|
110019
110590
|
}
|
|
110020
110591
|
if (deployment.status === "failed") {
|
|
110021
|
-
const { error: error48, recovery, summary } = await classifyDeploymentFailure({
|
|
110592
|
+
const { error: error48, recovery: recovery2, summary: summary2 } = await classifyDeploymentFailure({
|
|
110022
110593
|
ctx,
|
|
110023
110594
|
app,
|
|
110024
110595
|
deployment,
|
|
@@ -110031,8 +110602,8 @@ async function waitForDeploy(ctx, input, opts) {
|
|
|
110031
110602
|
elapsedSeconds: Math.round((Date.now() - startedAt) / 1000),
|
|
110032
110603
|
totalElapsedSeconds: secondsSinceCreated(deployment),
|
|
110033
110604
|
error: error48,
|
|
110034
|
-
recovery,
|
|
110035
|
-
summary
|
|
110605
|
+
recovery: recovery2,
|
|
110606
|
+
summary: summary2
|
|
110036
110607
|
};
|
|
110037
110608
|
}
|
|
110038
110609
|
if (deployment.isCheck && deployment.checkPassed) {
|
|
@@ -110233,7 +110804,7 @@ async function doctor(ctx, input = {}) {
|
|
|
110233
110804
|
});
|
|
110234
110805
|
return summarize(checks3, { appProvided: !!input.app });
|
|
110235
110806
|
}
|
|
110236
|
-
const tomlPath =
|
|
110807
|
+
const tomlPath = join14(ctx.cwd, "percher.toml");
|
|
110237
110808
|
const tomlExists = existsSync9(tomlPath);
|
|
110238
110809
|
let tomlValid = false;
|
|
110239
110810
|
let tomlProblems;
|
|
@@ -110253,7 +110824,7 @@ async function doctor(ctx, input = {}) {
|
|
|
110253
110824
|
tomlProblems = tomlErrorToRecoveryProblems(err);
|
|
110254
110825
|
}
|
|
110255
110826
|
if (err instanceof PercherTomlError && err.issues && err.issues.length > 0) {
|
|
110256
|
-
const
|
|
110827
|
+
const summary2 = err.issues.slice(0, 3).map((i) => {
|
|
110257
110828
|
const where = i.path.length > 0 ? `[${i.path.join(".")}]` : "(root)";
|
|
110258
110829
|
return `${where} ${i.message}`;
|
|
110259
110830
|
}).join("; ");
|
|
@@ -110261,7 +110832,7 @@ async function doctor(ctx, input = {}) {
|
|
|
110261
110832
|
checks3.push({
|
|
110262
110833
|
name: "percher.toml",
|
|
110263
110834
|
status: "fail",
|
|
110264
|
-
message: `${
|
|
110835
|
+
message: `${summary2}${more}`
|
|
110265
110836
|
});
|
|
110266
110837
|
} else {
|
|
110267
110838
|
checks3.push({
|
|
@@ -110748,7 +111319,7 @@ var VERDICT_RULES = [
|
|
|
110748
111319
|
const reasonCode = vctx.lastDeployStatus === "queued" ? "deploy_queued" : vctx.lastDeployStatus === "building" ? "deploy_building" : vctx.lastDeployStatus === "deploying" ? "deploy_deploying" : "deploy_queued";
|
|
110749
111320
|
const what = inTransitionalApp ? `App ${vctx.appName ?? ""} is provisioning` : `Last deploy is ${vctx.lastDeployStatus}`;
|
|
110750
111321
|
const waiting = inTransitionalApp ? "This app is still provisioning" : reasonCode === "deploy_building" ? "The last deploy is still building" : reasonCode === "deploy_deploying" ? "The last deploy is being rolled out" : "The last deploy is still queued";
|
|
110751
|
-
const
|
|
111322
|
+
const recovery2 = vctx.lastDeployId && vctx.appName ? recoveryWait({
|
|
110752
111323
|
app: vctx.appName,
|
|
110753
111324
|
deployId: vctx.lastDeployId,
|
|
110754
111325
|
reasonCode
|
|
@@ -110764,7 +111335,7 @@ var VERDICT_RULES = [
|
|
|
110764
111335
|
reasonCode,
|
|
110765
111336
|
phase: "deploy"
|
|
110766
111337
|
},
|
|
110767
|
-
recovery,
|
|
111338
|
+
recovery: recovery2,
|
|
110768
111339
|
summary: vctx.lastDeployId ? `${what.trim()} — wait for deploy ${vctx.lastDeployId}.` : `${what.trim()} — wait a moment and re-run.`
|
|
110769
111340
|
};
|
|
110770
111341
|
}
|
|
@@ -111032,7 +111603,7 @@ var domainRemoveInputSchema = exports_external.object({
|
|
|
111032
111603
|
app: exports_external.string().optional(),
|
|
111033
111604
|
domain: exports_external.string().min(1, "Domain is required")
|
|
111034
111605
|
});
|
|
111035
|
-
function
|
|
111606
|
+
function resolveApp2(ctx, app) {
|
|
111036
111607
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
111037
111608
|
if (!name) {
|
|
111038
111609
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -111043,19 +111614,19 @@ function resolveApp(ctx, app) {
|
|
|
111043
111614
|
return name;
|
|
111044
111615
|
}
|
|
111045
111616
|
async function domainAdd(ctx, input) {
|
|
111046
|
-
const appRef2 =
|
|
111617
|
+
const appRef2 = resolveApp2(ctx, input.app);
|
|
111047
111618
|
return ctx.client.apps.addDomain(appRef2, input.domain);
|
|
111048
111619
|
}
|
|
111049
111620
|
async function domainVerify(ctx, input) {
|
|
111050
|
-
const appRef2 =
|
|
111621
|
+
const appRef2 = resolveApp2(ctx, input.app);
|
|
111051
111622
|
return ctx.client.apps.verifyDomain(appRef2, input.domain);
|
|
111052
111623
|
}
|
|
111053
111624
|
async function domainList(ctx, input = {}) {
|
|
111054
|
-
const appRef2 =
|
|
111625
|
+
const appRef2 = resolveApp2(ctx, input.app);
|
|
111055
111626
|
return ctx.client.apps.listDomains(appRef2);
|
|
111056
111627
|
}
|
|
111057
111628
|
async function domainRemove(ctx, input) {
|
|
111058
|
-
const appRef2 =
|
|
111629
|
+
const appRef2 = resolveApp2(ctx, input.app);
|
|
111059
111630
|
await ctx.client.apps.removeDomain(appRef2, input.domain);
|
|
111060
111631
|
}
|
|
111061
111632
|
// ../core/dist/commands/env.js
|
|
@@ -111249,8 +111820,8 @@ var forgejoSetupWebhookInputSchema = exports_external.object({
|
|
|
111249
111820
|
app: exports_external.string().optional().describe("App name (overrides percher.toml)")
|
|
111250
111821
|
});
|
|
111251
111822
|
// ../core/dist/commands/generate.js
|
|
111252
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
111253
|
-
import { join as
|
|
111823
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
111824
|
+
import { join as join15 } from "node:path";
|
|
111254
111825
|
var generateInputSchema = exports_external.object({
|
|
111255
111826
|
cwd: exports_external.string().optional()
|
|
111256
111827
|
});
|
|
@@ -111336,7 +111907,7 @@ function generateTypeScript(config2) {
|
|
|
111336
111907
|
}
|
|
111337
111908
|
async function generate(ctx, input = {}) {
|
|
111338
111909
|
const cwd = input.cwd ?? ctx.cwd;
|
|
111339
|
-
const tomlPath =
|
|
111910
|
+
const tomlPath = join15(cwd, "percher.toml");
|
|
111340
111911
|
if (!existsSync10(tomlPath)) {
|
|
111341
111912
|
throw new PercherCoreError("No percher.toml found", {
|
|
111342
111913
|
code: "dev.no-app",
|
|
@@ -111346,14 +111917,14 @@ async function generate(ctx, input = {}) {
|
|
|
111346
111917
|
const config2 = await parseFile(tomlPath);
|
|
111347
111918
|
const files = [];
|
|
111348
111919
|
const envExample = generateEnvExample(config2);
|
|
111349
|
-
|
|
111920
|
+
writeFileSync7(join15(cwd, ".env.example"), envExample);
|
|
111350
111921
|
files.push(".env.example");
|
|
111351
111922
|
const tsTypes = generateTypeScript(config2);
|
|
111352
|
-
|
|
111923
|
+
writeFileSync7(join15(cwd, "percher.generated.d.ts"), tsTypes);
|
|
111353
111924
|
files.push("percher.generated.d.ts");
|
|
111354
111925
|
const agentInstructions = generateAgentInstructions(config2);
|
|
111355
|
-
|
|
111356
|
-
|
|
111926
|
+
mkdirSync7(join15(cwd, ".percher"), { recursive: true });
|
|
111927
|
+
writeFileSync7(join15(cwd, ".percher", "agent-instructions.md"), agentInstructions);
|
|
111357
111928
|
files.push(".percher/agent-instructions.md");
|
|
111358
111929
|
return { files };
|
|
111359
111930
|
}
|
|
@@ -111403,7 +111974,7 @@ var githubConnectInputSchema = exports_external.object({
|
|
|
111403
111974
|
branch: exports_external.string().optional().describe("Branch to deploy and track (default: main)"),
|
|
111404
111975
|
autoPreviews: exports_external.boolean().optional().describe("Opt-in: push to a non-tracked branch creates a preview deploy at <app>--p-<branch-slug>.percher.run. Default false.")
|
|
111405
111976
|
});
|
|
111406
|
-
function
|
|
111977
|
+
function resolveApp3(ctx, app) {
|
|
111407
111978
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
111408
111979
|
if (!name) {
|
|
111409
111980
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -111414,7 +111985,7 @@ function resolveApp2(ctx, app) {
|
|
|
111414
111985
|
return name;
|
|
111415
111986
|
}
|
|
111416
111987
|
async function githubConnect(ctx, input) {
|
|
111417
|
-
const appRef2 =
|
|
111988
|
+
const appRef2 = resolveApp3(ctx, input.app);
|
|
111418
111989
|
const branch = input.branch ?? "main";
|
|
111419
111990
|
let deployment;
|
|
111420
111991
|
let created;
|
|
@@ -111494,7 +112065,7 @@ var githubSetupWebhookInputSchema = exports_external.object({
|
|
|
111494
112065
|
app: exports_external.string().optional().describe("App name (overrides percher.toml)")
|
|
111495
112066
|
});
|
|
111496
112067
|
async function githubSetupWebhook(ctx, input) {
|
|
111497
|
-
const appRef2 =
|
|
112068
|
+
const appRef2 = resolveApp3(ctx, input.app);
|
|
111498
112069
|
const webhook = await ctx.client.apps.setupWebhook(appRef2);
|
|
111499
112070
|
const repoBase = webhook.instructions.repo.replace(/\.git$/, "");
|
|
111500
112071
|
return {
|
|
@@ -111559,11 +112130,17 @@ async function hookRevoke(ctx, input) {
|
|
|
111559
112130
|
await ctx.client.hooks.revoke(app.id, input.id);
|
|
111560
112131
|
}
|
|
111561
112132
|
// ../core/dist/commands/import-project.js
|
|
111562
|
-
import { existsSync as existsSync11, readFileSync as
|
|
111563
|
-
import { join as
|
|
112133
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "node:fs";
|
|
112134
|
+
import { join as join16 } from "node:path";
|
|
111564
112135
|
|
|
111565
112136
|
// ../core/dist/static-docker.js
|
|
111566
112137
|
var STATIC_DOCKER_PORT = 8080;
|
|
112138
|
+
var INIT_TEMPLATE_FRAMEWORKS = new Set([
|
|
112139
|
+
"astro",
|
|
112140
|
+
"preact",
|
|
112141
|
+
"solid",
|
|
112142
|
+
"vite"
|
|
112143
|
+
]);
|
|
111567
112144
|
function renderStaticFrameworkDockerfile(input) {
|
|
111568
112145
|
return `# Multi-stage build: a Bun stage compiles the static bundle, then a
|
|
111569
112146
|
# minimal Caddy image serves it. This project uses runtime = "docker"
|
|
@@ -111581,7 +112158,7 @@ RUN bun install && bun run build
|
|
|
111581
112158
|
# Build pinned Caddy source with refreshed security modules. The scratch
|
|
111582
112159
|
# runtime carries no shell, package manager, or file capabilities and listens
|
|
111583
112160
|
# on the unprivileged port :${STATIC_DOCKER_PORT}.
|
|
111584
|
-
FROM golang:1.26.
|
|
112161
|
+
FROM golang:1.26.9-alpine3.23@sha256:6750308561953d451210ed1a8086d36c8c8bdcbf672d38d9d0d424b8a7a0216c AS caddy-source
|
|
111585
112162
|
ADD --checksum=sha256:78e660d838e45c0b8c89338b325946238f153641aa9925df9ef2ad5e8eced31b \\
|
|
111586
112163
|
https://github.com/caddyserver/caddy/commit/b2693fb63a30e6d7be0972c3645e9a2c0a500e93.patch /tmp/caddy-cel-go.patch
|
|
111587
112164
|
RUN go mod download github.com/caddyserver/caddy/v2@v2.11.4 \\
|
|
@@ -111591,9 +112168,15 @@ WORKDIR /src
|
|
|
111591
112168
|
RUN apk add --no-cache patch \\
|
|
111592
112169
|
&& patch -p1 < /tmp/caddy-cel-go.patch \\
|
|
111593
112170
|
&& go get github.com/go-chi/chi/v5@v5.3.0 github.com/google/cel-go@v0.29.2 \\
|
|
111594
|
-
github.com/klauspost/compress@v1.18.7 go.opentelemetry.io/otel@v1.
|
|
111595
|
-
|
|
111596
|
-
|
|
112171
|
+
github.com/klauspost/compress@v1.18.7 go.opentelemetry.io/otel@v1.45.0 \\
|
|
112172
|
+
go.opentelemetry.io/otel/sdk/log@v0.21.0 \\
|
|
112173
|
+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc@v0.21.0 \\
|
|
112174
|
+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp@v0.21.0 \\
|
|
112175
|
+
go.opentelemetry.io/otel/exporters/stdout/stdoutlog@v0.21.0 \\
|
|
112176
|
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@v1.45.0 \\
|
|
112177
|
+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.45.0 \\
|
|
112178
|
+
golang.org/x/crypto@v0.57.0 golang.org/x/net@v0.60.0 \\
|
|
112179
|
+
golang.org/x/text@v0.42.0 google.golang.org/grpc@v1.83.2 \\
|
|
111597
112180
|
&& go mod tidy \\
|
|
111598
112181
|
&& CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o /out/caddy ./cmd/caddy \\
|
|
111599
112182
|
&& printf '%s\\n' \\
|
|
@@ -111631,6 +112214,15 @@ ${body}
|
|
|
111631
112214
|
}
|
|
111632
112215
|
`;
|
|
111633
112216
|
}
|
|
112217
|
+
var TEMPLATE_GO_PINS = readGoPins(renderStaticFrameworkDockerfile({ outputDir: "dist" }));
|
|
112218
|
+
function readGoPins(dockerfile) {
|
|
112219
|
+
const modules = {};
|
|
112220
|
+
for (const m of dockerfile.matchAll(/([a-z0-9-]+(?:\.[a-z0-9-]+)+\/[^\s@\\]+)@v(\d[^\s\\]*)/g)) {
|
|
112221
|
+
if (m[1] && m[2])
|
|
112222
|
+
modules[m[1]] = m[2];
|
|
112223
|
+
}
|
|
112224
|
+
return { go: /^FROM golang:(\d+\.\d+\.\d+)/m.exec(dockerfile)?.[1] ?? null, modules };
|
|
112225
|
+
}
|
|
111634
112226
|
|
|
111635
112227
|
// ../core/dist/commands/import-project.js
|
|
111636
112228
|
var importInputSchema = exports_external.object({
|
|
@@ -111638,9 +112230,9 @@ var importInputSchema = exports_external.object({
|
|
|
111638
112230
|
app: exports_external.string().optional().describe("App name to import into")
|
|
111639
112231
|
});
|
|
111640
112232
|
function detectProvider(cwd) {
|
|
111641
|
-
if (existsSync11(
|
|
112233
|
+
if (existsSync11(join16(cwd, "vercel.json")))
|
|
111642
112234
|
return "vercel";
|
|
111643
|
-
if (existsSync11(
|
|
112235
|
+
if (existsSync11(join16(cwd, "netlify.toml")))
|
|
111644
112236
|
return "netlify";
|
|
111645
112237
|
return null;
|
|
111646
112238
|
}
|
|
@@ -111976,7 +112568,7 @@ function mapVercelFramework(framework) {
|
|
|
111976
112568
|
return map2[framework ?? ""] ?? { runtime: "node" };
|
|
111977
112569
|
}
|
|
111978
112570
|
function parseVercelJson(cwd) {
|
|
111979
|
-
const raw =
|
|
112571
|
+
const raw = readFileSync9(join16(cwd, "vercel.json"), "utf-8");
|
|
111980
112572
|
const config2 = JSON.parse(raw);
|
|
111981
112573
|
const warnings = [];
|
|
111982
112574
|
const envVars = [];
|
|
@@ -112032,12 +112624,12 @@ health = "/api/health"
|
|
|
112032
112624
|
return { toml, warnings, envVars, staticBuild, redirects, headers };
|
|
112033
112625
|
}
|
|
112034
112626
|
function parseNetlifyToml(cwd) {
|
|
112035
|
-
const raw =
|
|
112627
|
+
const raw = readFileSync9(join16(cwd, "netlify.toml"), "utf-8");
|
|
112036
112628
|
const warnings = [];
|
|
112037
112629
|
const envVars = [];
|
|
112038
112630
|
const buildCommand = raw.match(/command\s*=\s*"([^"]+)"/)?.[1] ?? "bun run build";
|
|
112039
112631
|
const publishDir = raw.match(/publish\s*=\s*"([^"]+)"/)?.[1] ?? "dist";
|
|
112040
|
-
const hasPackageJson = existsSync11(
|
|
112632
|
+
const hasPackageJson = existsSync11(join16(cwd, "package.json"));
|
|
112041
112633
|
const looksLikeStaticOutput = publishDir === "dist" || publishDir === "build" || publishDir === "public";
|
|
112042
112634
|
let toml = `[app]
|
|
112043
112635
|
name = "imported-app"
|
|
@@ -112085,23 +112677,23 @@ health = "/health"
|
|
|
112085
112677
|
}
|
|
112086
112678
|
}
|
|
112087
112679
|
const sidecarPath = (name) => {
|
|
112088
|
-
const root =
|
|
112680
|
+
const root = join16(cwd, name);
|
|
112089
112681
|
if (existsSync11(root))
|
|
112090
112682
|
return root;
|
|
112091
|
-
const published =
|
|
112683
|
+
const published = join16(cwd, publishDir, name);
|
|
112092
112684
|
return existsSync11(published) ? published : null;
|
|
112093
112685
|
};
|
|
112094
112686
|
const redirectCollector = newRedirectCollector();
|
|
112095
112687
|
const redirectsPath = sidecarPath("_redirects");
|
|
112096
112688
|
if (redirectsPath) {
|
|
112097
|
-
parseNetlifyRedirectsFile(
|
|
112689
|
+
parseNetlifyRedirectsFile(readFileSync9(redirectsPath, "utf-8"), redirectCollector, warnings);
|
|
112098
112690
|
}
|
|
112099
112691
|
parseNetlifyTomlRedirects(raw, redirectCollector, warnings);
|
|
112100
112692
|
const redirects = finishRedirects(redirectCollector, warnings, "netlify");
|
|
112101
112693
|
const headerTable = {};
|
|
112102
112694
|
const headersPath = sidecarPath("_headers");
|
|
112103
112695
|
if (headersPath) {
|
|
112104
|
-
parseNetlifyHeadersFile(
|
|
112696
|
+
parseNetlifyHeadersFile(readFileSync9(headersPath, "utf-8"), headerTable, warnings);
|
|
112105
112697
|
}
|
|
112106
112698
|
const headers = finishHeaders(headerTable, warnings, "_headers");
|
|
112107
112699
|
if (/^\s*\[\[headers\]\]/m.test(raw)) {
|
|
@@ -112170,11 +112762,11 @@ ${serialize(extras)}`;
|
|
|
112170
112762
|
mapped.headerPaths = Object.keys(headers).length;
|
|
112171
112763
|
}
|
|
112172
112764
|
}
|
|
112173
|
-
const tomlPath =
|
|
112765
|
+
const tomlPath = join16(ctx.cwd, "percher.toml");
|
|
112174
112766
|
if (existsSync11(tomlPath)) {
|
|
112175
112767
|
result.warnings.unshift("percher.toml already exists — overwriting with imported config");
|
|
112176
112768
|
}
|
|
112177
|
-
|
|
112769
|
+
writeFileSync8(tomlPath, toml);
|
|
112178
112770
|
const scaffoldedFiles = [];
|
|
112179
112771
|
if (result.staticBuild) {
|
|
112180
112772
|
const targets = [
|
|
@@ -112188,12 +112780,12 @@ ${serialize(extras)}`;
|
|
|
112188
112780
|
}
|
|
112189
112781
|
];
|
|
112190
112782
|
for (const { name, content } of targets) {
|
|
112191
|
-
const
|
|
112192
|
-
if (existsSync11(
|
|
112783
|
+
const target2 = join16(ctx.cwd, name);
|
|
112784
|
+
if (existsSync11(target2)) {
|
|
112193
112785
|
result.warnings.push(`${name} already exists — left untouched. The imported config expects a multi-stage static build; merge by hand if needed.`);
|
|
112194
112786
|
continue;
|
|
112195
112787
|
}
|
|
112196
|
-
|
|
112788
|
+
writeFileSync8(target2, content, "utf-8");
|
|
112197
112789
|
scaffoldedFiles.push(name);
|
|
112198
112790
|
}
|
|
112199
112791
|
}
|
|
@@ -112215,12 +112807,12 @@ function parsesAsPercherToml(source) {
|
|
|
112215
112807
|
}
|
|
112216
112808
|
}
|
|
112217
112809
|
// ../core/dist/commands/init.js
|
|
112218
|
-
import { existsSync as existsSync13, writeFileSync as
|
|
112219
|
-
import { basename as basename3, join as
|
|
112810
|
+
import { existsSync as existsSync13, writeFileSync as writeFileSync9 } from "node:fs";
|
|
112811
|
+
import { basename as basename3, join as join18 } from "node:path";
|
|
112220
112812
|
|
|
112221
112813
|
// ../core/dist/detect.js
|
|
112222
|
-
import { existsSync as existsSync12, readFileSync as
|
|
112223
|
-
import { join as
|
|
112814
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
|
|
112815
|
+
import { join as join17 } from "node:path";
|
|
112224
112816
|
function readPackageJson(src) {
|
|
112225
112817
|
const raw = src.text("package.json");
|
|
112226
112818
|
if (raw === null)
|
|
@@ -112392,10 +112984,10 @@ function detectFromSource(src) {
|
|
|
112392
112984
|
}
|
|
112393
112985
|
async function detectFramework(cwd) {
|
|
112394
112986
|
const src = {
|
|
112395
|
-
has: (...names) => names.some((n) => existsSync12(
|
|
112987
|
+
has: (...names) => names.some((n) => existsSync12(join17(cwd, n))),
|
|
112396
112988
|
text: (name) => {
|
|
112397
112989
|
try {
|
|
112398
|
-
return
|
|
112990
|
+
return readFileSync10(join17(cwd, name), "utf8");
|
|
112399
112991
|
} catch {
|
|
112400
112992
|
return null;
|
|
112401
112993
|
}
|
|
@@ -112404,7 +112996,7 @@ async function detectFramework(cwd) {
|
|
|
112404
112996
|
return detectFromSource(src);
|
|
112405
112997
|
}
|
|
112406
112998
|
function refineBunRuntime(detected, cwd) {
|
|
112407
|
-
if (detected.runtime === "node" && (existsSync12(
|
|
112999
|
+
if (detected.runtime === "node" && (existsSync12(join17(cwd, "bun.lockb")) || existsSync12(join17(cwd, "bun.lock")))) {
|
|
112408
113000
|
return { ...detected, runtime: "bun" };
|
|
112409
113001
|
}
|
|
112410
113002
|
return detected;
|
|
@@ -112438,7 +113030,24 @@ function configFromDetection(name, detected, dataMode) {
|
|
|
112438
113030
|
}
|
|
112439
113031
|
|
|
112440
113032
|
// ../core/dist/validation/blocked-names.js
|
|
113033
|
+
var SENSITIVE_BRANDS = new Set([
|
|
113034
|
+
"paypal",
|
|
113035
|
+
"bankid",
|
|
113036
|
+
"swish",
|
|
113037
|
+
"swedbank",
|
|
113038
|
+
"handelsbanken",
|
|
113039
|
+
"nordea",
|
|
113040
|
+
"seb",
|
|
113041
|
+
"danskebank",
|
|
113042
|
+
"mitid",
|
|
113043
|
+
"nemid",
|
|
113044
|
+
"mobilepay",
|
|
113045
|
+
"vipps",
|
|
113046
|
+
"klarna",
|
|
113047
|
+
"skatteverket"
|
|
113048
|
+
]);
|
|
112441
113049
|
var BLOCKED_APP_NAMES = new Set([
|
|
113050
|
+
...SENSITIVE_BRANDS,
|
|
112442
113051
|
"api",
|
|
112443
113052
|
"app",
|
|
112444
113053
|
"admin",
|
|
@@ -112497,6 +113106,8 @@ var BLOCKED_APP_NAMES = new Set([
|
|
|
112497
113106
|
function isBlockedName(name) {
|
|
112498
113107
|
if (BLOCKED_APP_NAMES.has(name))
|
|
112499
113108
|
return true;
|
|
113109
|
+
if (name.split("-").some((part) => SENSITIVE_BRANDS.has(part)))
|
|
113110
|
+
return true;
|
|
112500
113111
|
const prefixes = [
|
|
112501
113112
|
"login-",
|
|
112502
113113
|
"signin-",
|
|
@@ -112534,6 +113145,8 @@ function adjustReservedName(name) {
|
|
|
112534
113145
|
let adjusted = `app-${name}`;
|
|
112535
113146
|
if (adjusted.length > 40)
|
|
112536
113147
|
adjusted = adjusted.slice(0, 40).replace(/-+$/g, "");
|
|
113148
|
+
if (isBlockedName(adjusted))
|
|
113149
|
+
return `app-${crypto.randomUUID().slice(0, 8)}`;
|
|
112537
113150
|
return adjusted;
|
|
112538
113151
|
}
|
|
112539
113152
|
function detectInteractive() {
|
|
@@ -112549,7 +113162,7 @@ function scanEnvVars(_cwd) {
|
|
|
112549
113162
|
return {};
|
|
112550
113163
|
}
|
|
112551
113164
|
async function init(ctx, input = {}) {
|
|
112552
|
-
const path =
|
|
113165
|
+
const path = join18(ctx.cwd, "percher.toml");
|
|
112553
113166
|
const exists = existsSync13(path);
|
|
112554
113167
|
if (exists && !input.force) {
|
|
112555
113168
|
throw new PercherCoreError("percher.toml already exists", {
|
|
@@ -112594,7 +113207,7 @@ async function init(ctx, input = {}) {
|
|
|
112594
113207
|
if (Object.keys(envVars).length > 0) {
|
|
112595
113208
|
config2.env = envVars;
|
|
112596
113209
|
}
|
|
112597
|
-
|
|
113210
|
+
writeFileSync9(path, serialize(config2), "utf8");
|
|
112598
113211
|
const scaffoldedFiles = [];
|
|
112599
113212
|
if (detected?.staticBuild) {
|
|
112600
113213
|
const targets = [
|
|
@@ -112610,10 +113223,10 @@ async function init(ctx, input = {}) {
|
|
|
112610
113223
|
}
|
|
112611
113224
|
];
|
|
112612
113225
|
for (const { name: name2, content } of targets) {
|
|
112613
|
-
const
|
|
112614
|
-
if (existsSync13(
|
|
113226
|
+
const target2 = join18(ctx.cwd, name2);
|
|
113227
|
+
if (existsSync13(target2) && !input.force)
|
|
112615
113228
|
continue;
|
|
112616
|
-
|
|
113229
|
+
writeFileSync9(target2, content, "utf8");
|
|
112617
113230
|
scaffoldedFiles.push(name2);
|
|
112618
113231
|
}
|
|
112619
113232
|
}
|
|
@@ -113147,7 +113760,7 @@ async function inspectSupabase(ctx, input) {
|
|
|
113147
113760
|
const storageBuckets = normalizeBuckets(schemaBlob.storageBuckets);
|
|
113148
113761
|
const authUsersCount = toFiniteNumber(schemaBlob.authUsersCount);
|
|
113149
113762
|
const warnings = collectWarnings(tables, storageBuckets, authUsersCount);
|
|
113150
|
-
const
|
|
113763
|
+
const summary2 = renderSummary({
|
|
113151
113764
|
projectRef: input.projectRef,
|
|
113152
113765
|
tables,
|
|
113153
113766
|
authUsersCount,
|
|
@@ -113162,7 +113775,7 @@ async function inspectSupabase(ctx, input) {
|
|
|
113162
113775
|
storageBuckets,
|
|
113163
113776
|
warnings,
|
|
113164
113777
|
recovery: recoveryNone(),
|
|
113165
|
-
summary
|
|
113778
|
+
summary: summary2
|
|
113166
113779
|
};
|
|
113167
113780
|
}
|
|
113168
113781
|
function failure(args) {
|
|
@@ -113690,7 +114303,7 @@ function collectWarnings2(collections, rlsPolicies, unsupported) {
|
|
|
113690
114303
|
}
|
|
113691
114304
|
// ../core/dist/commands/migrate-supabase-rewrite.js
|
|
113692
114305
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
113693
|
-
import { dirname as
|
|
114306
|
+
import { dirname as dirname7, join as join21, relative as relative7, resolve as resolve9, sep as sep5 } from "node:path";
|
|
113694
114307
|
|
|
113695
114308
|
// ../core/dist/commands/migrate-supabase-recipes.js
|
|
113696
114309
|
var AUTH_RECIPES = {
|
|
@@ -113956,7 +114569,7 @@ function isSupabaseClientModule(source) {
|
|
|
113956
114569
|
// ../core/dist/commands/migrate-supabase-status.js
|
|
113957
114570
|
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
113958
114571
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
113959
|
-
import { join as
|
|
114572
|
+
import { join as join20, relative as relative6, resolve as resolve8 } from "node:path";
|
|
113960
114573
|
|
|
113961
114574
|
// ../core/dist/commands/migrate-supabase-sdk.js
|
|
113962
114575
|
var import_jscodeshift2 = __toESM(require_core3(), 1);
|
|
@@ -114173,12 +114786,12 @@ function isSupabaseFromTerminal(path, supabaseNames) {
|
|
|
114173
114786
|
let fromCall = null;
|
|
114174
114787
|
let cursor = path.node;
|
|
114175
114788
|
while (cursor.type === "CallExpression") {
|
|
114176
|
-
const
|
|
114177
|
-
if (
|
|
114789
|
+
const call2 = cursor;
|
|
114790
|
+
if (call2.callee.type !== "MemberExpression")
|
|
114178
114791
|
break;
|
|
114179
|
-
const callee =
|
|
114792
|
+
const callee = call2.callee;
|
|
114180
114793
|
if (callee.property.type === "Identifier" && callee.property.name === "from") {
|
|
114181
|
-
fromCall =
|
|
114794
|
+
fromCall = call2;
|
|
114182
114795
|
break;
|
|
114183
114796
|
}
|
|
114184
114797
|
cursor = callee.object;
|
|
@@ -114233,15 +114846,15 @@ function decomposeFromChain(outer) {
|
|
|
114233
114846
|
const reversedSteps = [];
|
|
114234
114847
|
let node = outer;
|
|
114235
114848
|
while (node.type === "CallExpression") {
|
|
114236
|
-
const
|
|
114237
|
-
if (
|
|
114849
|
+
const call2 = node;
|
|
114850
|
+
if (call2.callee.type !== "MemberExpression")
|
|
114238
114851
|
break;
|
|
114239
|
-
const callee =
|
|
114852
|
+
const callee = call2.callee;
|
|
114240
114853
|
const method = callee.property.type === "Identifier" ? callee.property.name : null;
|
|
114241
114854
|
if (method === null)
|
|
114242
114855
|
return null;
|
|
114243
114856
|
if (method === "from") {
|
|
114244
|
-
const arg =
|
|
114857
|
+
const arg = call2.arguments[0];
|
|
114245
114858
|
if (!arg || arg.type !== "Literal" && arg.type !== "StringLiteral")
|
|
114246
114859
|
return null;
|
|
114247
114860
|
const table = arg.value;
|
|
@@ -114249,7 +114862,7 @@ function decomposeFromChain(outer) {
|
|
|
114249
114862
|
return null;
|
|
114250
114863
|
return { table, steps: reversedSteps.reverse() };
|
|
114251
114864
|
}
|
|
114252
|
-
reversedSteps.push({ method, args:
|
|
114865
|
+
reversedSteps.push({ method, args: call2.arguments });
|
|
114253
114866
|
node = callee.object;
|
|
114254
114867
|
}
|
|
114255
114868
|
return null;
|
|
@@ -114674,14 +115287,14 @@ function readChainSteps(outer) {
|
|
|
114674
115287
|
let cursor = outer;
|
|
114675
115288
|
while (true) {
|
|
114676
115289
|
if (cursor.type === "CallExpression") {
|
|
114677
|
-
const
|
|
114678
|
-
if (
|
|
115290
|
+
const call2 = cursor;
|
|
115291
|
+
if (call2.callee.type !== "MemberExpression")
|
|
114679
115292
|
break;
|
|
114680
|
-
const callee =
|
|
115293
|
+
const callee = call2.callee;
|
|
114681
115294
|
if (callee.property.type === "Identifier") {
|
|
114682
115295
|
reversed.push({
|
|
114683
115296
|
method: callee.property.name,
|
|
114684
|
-
call
|
|
115297
|
+
call: call2
|
|
114685
115298
|
});
|
|
114686
115299
|
}
|
|
114687
115300
|
cursor = callee.object;
|
|
@@ -114702,8 +115315,8 @@ function readChainSteps(outer) {
|
|
|
114702
115315
|
}
|
|
114703
115316
|
return reversed.reverse();
|
|
114704
115317
|
}
|
|
114705
|
-
function readFirstStringArg(
|
|
114706
|
-
const a =
|
|
115318
|
+
function readFirstStringArg(call2) {
|
|
115319
|
+
const a = call2.arguments[0];
|
|
114707
115320
|
if (!a)
|
|
114708
115321
|
return null;
|
|
114709
115322
|
if (a.type === "Literal" || a.type === "StringLiteral") {
|
|
@@ -114893,7 +115506,7 @@ function applyRewrite(path, replacement, kind, pattern, note, flags, state) {
|
|
|
114893
115506
|
// ../core/dist/commands/migrate-supabase-walker.js
|
|
114894
115507
|
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
114895
115508
|
import { mkdir as mkdir2, readdir, readFile as readFile3, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
114896
|
-
import { dirname as
|
|
115509
|
+
import { dirname as dirname6, isAbsolute as isAbsolute3, join as join19, relative as relative5, resolve as resolve7, sep as sep4 } from "node:path";
|
|
114897
115510
|
var REWRITABLE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
114898
115511
|
var DEFAULT_EXCLUDES = [
|
|
114899
115512
|
"node_modules",
|
|
@@ -115045,7 +115658,7 @@ async function* walkTree(dir, rootAbs, ig) {
|
|
|
115045
115658
|
return;
|
|
115046
115659
|
}
|
|
115047
115660
|
for (const name of entries) {
|
|
115048
|
-
const abs =
|
|
115661
|
+
const abs = join19(dir, name);
|
|
115049
115662
|
const rel = relative5(rootAbs, abs).split(sep4).join("/");
|
|
115050
115663
|
if (rel.length > 0 && ig.ignores(rel))
|
|
115051
115664
|
continue;
|
|
@@ -115207,7 +115820,7 @@ async function writeWalkResult(input) {
|
|
|
115207
115820
|
if (rel.length === 0 || isParentTraversal || isAbsolute3(rel)) {
|
|
115208
115821
|
throw new Error(`writeWalkResult refused path-traversing file "${file2.relativePath}" → "${abs}" (would escape targetDir "${targetAbs}").`);
|
|
115209
115822
|
}
|
|
115210
|
-
await mkdir2(
|
|
115823
|
+
await mkdir2(dirname6(abs), { recursive: true });
|
|
115211
115824
|
await writeFile2(abs, file2.rewritten, "utf8");
|
|
115212
115825
|
written.push(file2.relativePath);
|
|
115213
115826
|
}
|
|
@@ -115448,11 +116061,11 @@ async function migrationStatus(ctx, input) {
|
|
|
115448
116061
|
const warning = analysis.checks.filter((c) => c.status === "warn");
|
|
115449
116062
|
const buildFailed = build?.ran === true && !build.passed;
|
|
115450
116063
|
const allGreen = failing.length === 0 && warning.length === 0 && !buildFailed;
|
|
115451
|
-
const
|
|
116064
|
+
const recovery2 = allGreen ? recoveryNone() : recoveryAsk({
|
|
115452
116065
|
prompt: buildPrompt(analysis.state, failing, warning, build),
|
|
115453
116066
|
reasonCode: "unknown"
|
|
115454
116067
|
});
|
|
115455
|
-
const
|
|
116068
|
+
const summary2 = `${STATE_SUMMARY[analysis.state]}${build ? ` Build: ${build.ran ? build.passed ? "passed" : "FAILED" : "skipped"}.` : ""}`;
|
|
115456
116069
|
return {
|
|
115457
116070
|
status: "ok",
|
|
115458
116071
|
rootDir: rootAbs,
|
|
@@ -115460,8 +116073,8 @@ async function migrationStatus(ctx, input) {
|
|
|
115460
116073
|
migrationComplete: analysis.migrationComplete,
|
|
115461
116074
|
checks: analysis.checks,
|
|
115462
116075
|
...build ? { build } : {},
|
|
115463
|
-
recovery,
|
|
115464
|
-
summary,
|
|
116076
|
+
recovery: recovery2,
|
|
116077
|
+
summary: summary2,
|
|
115465
116078
|
checklist
|
|
115466
116079
|
};
|
|
115467
116080
|
}
|
|
@@ -115482,7 +116095,7 @@ function buildPrompt(state, failing, warning, build) {
|
|
|
115482
116095
|
async function readManualRlsCount(rootAbs) {
|
|
115483
116096
|
for (const dir of ["migration-preview", "."]) {
|
|
115484
116097
|
try {
|
|
115485
|
-
const notes = await readFile4(
|
|
116098
|
+
const notes = await readFile4(join20(rootAbs, dir, "MIGRATION_NOTES.md"), "utf8");
|
|
115486
116099
|
const m = notes.match(/\*\*RLS policies:\*\*\s*\d+\s*\((\d+)\s*need manual review\)/);
|
|
115487
116100
|
if (m?.[1] !== undefined)
|
|
115488
116101
|
return Number.parseInt(m[1], 10);
|
|
@@ -115494,7 +116107,7 @@ async function readManualRlsCount(rootAbs) {
|
|
|
115494
116107
|
async function runProjectBuild(rootAbs) {
|
|
115495
116108
|
let hasBuildScript = false;
|
|
115496
116109
|
try {
|
|
115497
|
-
const pkg = JSON.parse(await readFile4(
|
|
116110
|
+
const pkg = JSON.parse(await readFile4(join20(rootAbs, "package.json"), "utf8"));
|
|
115498
116111
|
hasBuildScript = typeof pkg.scripts?.build === "string";
|
|
115499
116112
|
} catch {
|
|
115500
116113
|
return { ran: false, passed: false, detail: "No readable package.json — nothing to build." };
|
|
@@ -115526,7 +116139,7 @@ ${tail}` : ""}`
|
|
|
115526
116139
|
async function detectPackageManager(rootAbs) {
|
|
115527
116140
|
const has = async (name) => {
|
|
115528
116141
|
try {
|
|
115529
|
-
await readFile4(
|
|
116142
|
+
await readFile4(join20(rootAbs, name), "utf8");
|
|
115530
116143
|
return true;
|
|
115531
116144
|
} catch {
|
|
115532
116145
|
return false;
|
|
@@ -115656,8 +116269,8 @@ async function rewriteSupabaseClient(ctx, input) {
|
|
|
115656
116269
|
flags.push(...scaffold.flags);
|
|
115657
116270
|
}
|
|
115658
116271
|
const reportNeeded = hadRewrites || flags.length > 0 || walk2.skipped.length > 0;
|
|
115659
|
-
const backupDir = apply && changed.length > 0 ?
|
|
115660
|
-
const rewriteTarget = apply ? rootAbs : input.outputDir ? resolve9(ctx.cwd, input.outputDir) :
|
|
116272
|
+
const backupDir = apply && changed.length > 0 ? join21(rootAbs, "migration-preview", "backup") : null;
|
|
116273
|
+
const rewriteTarget = apply ? rootAbs : input.outputDir ? resolve9(ctx.cwd, input.outputDir) : join21(rootAbs, "migration-preview", "rewritten");
|
|
115661
116274
|
const filesWritten = [];
|
|
115662
116275
|
let clientModuleWritten = null;
|
|
115663
116276
|
try {
|
|
@@ -115677,19 +116290,19 @@ async function rewriteSupabaseClient(ctx, input) {
|
|
|
115677
116290
|
changedOnly: true
|
|
115678
116291
|
});
|
|
115679
116292
|
for (const rel of out.written) {
|
|
115680
|
-
filesWritten.push(relative7(ctx.cwd,
|
|
116293
|
+
filesWritten.push(relative7(ctx.cwd, join21(rewriteTarget, rel)));
|
|
115681
116294
|
}
|
|
115682
116295
|
if (scaffold?.clientModule) {
|
|
115683
|
-
const moduleAbs =
|
|
115684
|
-
await mkdir3(
|
|
116296
|
+
const moduleAbs = join21(rewriteTarget, scaffold.clientModule.relativePath);
|
|
116297
|
+
await mkdir3(dirname7(moduleAbs), { recursive: true });
|
|
115685
116298
|
await writeFile3(moduleAbs, scaffold.clientModule.content, "utf8");
|
|
115686
116299
|
clientModuleWritten = relative7(ctx.cwd, moduleAbs).split(sep5).join("/");
|
|
115687
116300
|
filesWritten.push(clientModuleWritten);
|
|
115688
116301
|
}
|
|
115689
116302
|
}
|
|
115690
116303
|
if (reportNeeded) {
|
|
115691
|
-
const reportAbs =
|
|
115692
|
-
await mkdir3(
|
|
116304
|
+
const reportAbs = join21(rootAbs, "migration-preview", "REWRITE_NOTES.md");
|
|
116305
|
+
await mkdir3(dirname7(reportAbs), { recursive: true });
|
|
115693
116306
|
const analysis = analyzeMigration(walk2.files.map((f) => ({
|
|
115694
116307
|
relativePath: f.relativePath,
|
|
115695
116308
|
kind: f.kind,
|
|
@@ -115714,7 +116327,7 @@ async function rewriteSupabaseClient(ctx, input) {
|
|
|
115714
116327
|
for (const flag of flags) {
|
|
115715
116328
|
flagsByPattern[flag.pattern] = (flagsByPattern[flag.pattern] ?? 0) + 1;
|
|
115716
116329
|
}
|
|
115717
|
-
const
|
|
116330
|
+
const recovery2 = reportNeeded ? recoveryAsk({
|
|
115718
116331
|
prompt: buildPrompt2(flags, walk2.skipped.length, hadRewrites, clientModuleWritten),
|
|
115719
116332
|
reasonCode: "unknown"
|
|
115720
116333
|
}) : recoveryNone();
|
|
@@ -115732,7 +116345,7 @@ async function rewriteSupabaseClient(ctx, input) {
|
|
|
115732
116345
|
envFilesChanged: walk2.summary.envFilesChanged,
|
|
115733
116346
|
clientModule: clientModuleWritten,
|
|
115734
116347
|
skipped: walk2.skipped,
|
|
115735
|
-
recovery,
|
|
116348
|
+
recovery: recovery2,
|
|
115736
116349
|
summary: renderSummary2({
|
|
115737
116350
|
mode,
|
|
115738
116351
|
changed: changed.length,
|
|
@@ -115941,7 +116554,7 @@ function failure3(rootAbs, mode, err, suggestion) {
|
|
|
115941
116554
|
}
|
|
115942
116555
|
// ../core/dist/commands/migrate-supabase-schema.js
|
|
115943
116556
|
import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
115944
|
-
import { isAbsolute as isAbsolute4, join as
|
|
116557
|
+
import { isAbsolute as isAbsolute4, join as join22, relative as relative8, resolve as resolve10 } from "node:path";
|
|
115945
116558
|
|
|
115946
116559
|
// ../core/dist/commands/migrate-supabase-scripts.js
|
|
115947
116560
|
function generateDataImportScripts(preview) {
|
|
@@ -115974,13 +116587,13 @@ function topologicalSort(collections) {
|
|
|
115974
116587
|
for (const field of c.schema) {
|
|
115975
116588
|
if (field.type !== "relation")
|
|
115976
116589
|
continue;
|
|
115977
|
-
const
|
|
115978
|
-
if (
|
|
116590
|
+
const target2 = field.options.collectionName;
|
|
116591
|
+
if (target2 === c.name)
|
|
115979
116592
|
continue;
|
|
115980
|
-
if (!byName.has(
|
|
116593
|
+
if (!byName.has(target2))
|
|
115981
116594
|
continue;
|
|
115982
|
-
dependsOn.get(c.name)?.add(
|
|
115983
|
-
dependents.get(
|
|
116595
|
+
dependsOn.get(c.name)?.add(target2);
|
|
116596
|
+
dependents.get(target2)?.add(c.name);
|
|
115984
116597
|
}
|
|
115985
116598
|
}
|
|
115986
116599
|
const inputOrder = collections.map((c) => c.name);
|
|
@@ -116221,7 +116834,7 @@ function renderRowTransform(collection) {
|
|
|
116221
116834
|
}
|
|
116222
116835
|
for (const rel of relations) {
|
|
116223
116836
|
const fieldName = rel.name;
|
|
116224
|
-
const
|
|
116837
|
+
const target2 = rel.options.collectionName;
|
|
116225
116838
|
const isAuthUsersRef = rel.source.flag === "auth_users_reference";
|
|
116226
116839
|
if (isAuthUsersRef) {
|
|
116227
116840
|
parts.push(` if (rest[${JSON.stringify(fieldName)}] != null) {`);
|
|
@@ -116231,9 +116844,9 @@ function renderRowTransform(collection) {
|
|
|
116231
116844
|
continue;
|
|
116232
116845
|
}
|
|
116233
116846
|
parts.push(` if (rest[${JSON.stringify(fieldName)}] != null) {`);
|
|
116234
|
-
parts.push(` const mapped = lookupId(${JSON.stringify(
|
|
116847
|
+
parts.push(` const mapped = lookupId(${JSON.stringify(target2)}, rest[${JSON.stringify(fieldName)}]);`);
|
|
116235
116848
|
parts.push(" if (mapped === undefined) {");
|
|
116236
|
-
parts.push(` throw new Error(\`[${collection.name}.${fieldName}] no PB id for source value '\${rest[${JSON.stringify(fieldName)}]}' in ${
|
|
116849
|
+
parts.push(` throw new Error(\`[${collection.name}.${fieldName}] no PB id for source value '\${rest[${JSON.stringify(fieldName)}]}' in ${target2} map — was ${target2} migrated first?\`);`);
|
|
116237
116850
|
parts.push(" }");
|
|
116238
116851
|
parts.push(` rest[${JSON.stringify(fieldName)}] = mapped;`);
|
|
116239
116852
|
parts.push(" }");
|
|
@@ -116436,7 +117049,7 @@ async function migrateSupabaseSchema(ctx, input) {
|
|
|
116436
117049
|
}
|
|
116437
117050
|
};
|
|
116438
117051
|
}
|
|
116439
|
-
const
|
|
117052
|
+
const summary2 = renderSummary3({
|
|
116440
117053
|
projectRef: input.projectRef,
|
|
116441
117054
|
outputDirRel,
|
|
116442
117055
|
inspection,
|
|
@@ -116449,7 +117062,7 @@ async function migrateSupabaseSchema(ctx, input) {
|
|
|
116449
117062
|
filesWritten,
|
|
116450
117063
|
preview,
|
|
116451
117064
|
recovery: recoveryNone(),
|
|
116452
|
-
summary
|
|
117065
|
+
summary: summary2
|
|
116453
117066
|
};
|
|
116454
117067
|
}
|
|
116455
117068
|
function resolveOutputDir(cwd, requested) {
|
|
@@ -116461,10 +117074,10 @@ async function writePreviewFiles(ctx, outputDir, preview) {
|
|
|
116461
117074
|
const schemaJson = renderSchemaJson(preview);
|
|
116462
117075
|
const notesMd = renderMigrationNotes(preview);
|
|
116463
117076
|
const scripts = generateDataImportScripts(preview);
|
|
116464
|
-
const schemaPath =
|
|
116465
|
-
const notesPath =
|
|
116466
|
-
const migratePath =
|
|
116467
|
-
const storagePath =
|
|
117077
|
+
const schemaPath = join22(outputDir, "pb_schema.json");
|
|
117078
|
+
const notesPath = join22(outputDir, "MIGRATION_NOTES.md");
|
|
117079
|
+
const migratePath = join22(outputDir, "pb_migrate.js");
|
|
117080
|
+
const storagePath = join22(outputDir, "pb_migrate_storage.js");
|
|
116468
117081
|
await writeFile4(schemaPath, schemaJson, "utf8");
|
|
116469
117082
|
await writeFile4(notesPath, notesMd, "utf8");
|
|
116470
117083
|
await writeFile4(migratePath, scripts.pbMigrate, "utf8");
|
|
@@ -116549,8 +117162,8 @@ function renderMigrationNotes(preview) {
|
|
|
116549
117162
|
lines.push("| Field | Type | Required | Postgres source | Flag |");
|
|
116550
117163
|
lines.push("|---|---|---|---|---|");
|
|
116551
117164
|
for (const field of collection.schema) {
|
|
116552
|
-
const
|
|
116553
|
-
lines.push(`| \`${field.name}\` | ${
|
|
117165
|
+
const target2 = field.type === "relation" ? `relation → \`${field.options.collectionName}\`` : field.type;
|
|
117166
|
+
lines.push(`| \`${field.name}\` | ${target2} | ${field.required ? "yes" : "no"} | \`${field.source.postgresType}\` | ${field.source.flag ? `\`${field.source.flag}\`` : "—"} |`);
|
|
116554
117167
|
}
|
|
116555
117168
|
lines.push("");
|
|
116556
117169
|
}
|
|
@@ -116658,7 +117271,7 @@ var previewBranchSetInputSchema = exports_external.object({
|
|
|
116658
117271
|
var previewBranchInputSchema = exports_external.object({
|
|
116659
117272
|
app: exports_external.string().optional()
|
|
116660
117273
|
});
|
|
116661
|
-
function
|
|
117274
|
+
function resolveApp4(ctx, app) {
|
|
116662
117275
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
116663
117276
|
if (!name) {
|
|
116664
117277
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -116669,11 +117282,11 @@ function resolveApp3(ctx, app) {
|
|
|
116669
117282
|
return name;
|
|
116670
117283
|
}
|
|
116671
117284
|
async function previewBranchSet(ctx, input) {
|
|
116672
|
-
const appRef2 =
|
|
117285
|
+
const appRef2 = resolveApp4(ctx, input.app);
|
|
116673
117286
|
return ctx.client.apps.setPreviewBranch(appRef2, input.branch);
|
|
116674
117287
|
}
|
|
116675
117288
|
async function previewBranchUnset(ctx, input = {}) {
|
|
116676
|
-
const appRef2 =
|
|
117289
|
+
const appRef2 = resolveApp4(ctx, input.app);
|
|
116677
117290
|
return ctx.client.apps.unsetPreviewBranch(appRef2);
|
|
116678
117291
|
}
|
|
116679
117292
|
var setPreviewBranchToolInputSchema = exports_external.object({
|
|
@@ -116681,7 +117294,7 @@ var setPreviewBranchToolInputSchema = exports_external.object({
|
|
|
116681
117294
|
branch: exports_external.string().nullable().describe("Branch to pin as the preview address; pass null to clear it.")
|
|
116682
117295
|
});
|
|
116683
117296
|
async function previewBranchShow(ctx, input = {}) {
|
|
116684
|
-
const appRef2 =
|
|
117297
|
+
const appRef2 = resolveApp4(ctx, input.app);
|
|
116685
117298
|
const app = await ctx.client.apps.get(appRef2);
|
|
116686
117299
|
return {
|
|
116687
117300
|
previewBranch: app.previewBranch ?? null,
|
|
@@ -116690,14 +117303,14 @@ async function previewBranchShow(ctx, input = {}) {
|
|
|
116690
117303
|
};
|
|
116691
117304
|
}
|
|
116692
117305
|
async function previewList(ctx, input = {}) {
|
|
116693
|
-
const appRef2 =
|
|
117306
|
+
const appRef2 = resolveApp4(ctx, input.app);
|
|
116694
117307
|
const app = await ctx.client.apps.get(appRef2);
|
|
116695
117308
|
return { app: app.name, previews: app.previews ?? [] };
|
|
116696
117309
|
}
|
|
116697
117310
|
// ../core/dist/commands/publish.js
|
|
116698
117311
|
init_dist();
|
|
116699
117312
|
import { existsSync as existsSync15 } from "node:fs";
|
|
116700
|
-
import { join as
|
|
117313
|
+
import { join as join25 } from "node:path";
|
|
116701
117314
|
|
|
116702
117315
|
// ../shared/dist/pow.js
|
|
116703
117316
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -117101,8 +117714,8 @@ async function runDeployWithRetry(opts) {
|
|
|
117101
117714
|
|
|
117102
117715
|
// ../core/dist/commands/env-scan.js
|
|
117103
117716
|
init_dist();
|
|
117104
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
117105
|
-
import { join as
|
|
117717
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync11, statSync as statSync3 } from "node:fs";
|
|
117718
|
+
import { join as join23 } from "node:path";
|
|
117106
117719
|
function platformInjectedClientEnvKeys(config2) {
|
|
117107
117720
|
const data2 = config2.data;
|
|
117108
117721
|
if (!data2)
|
|
@@ -117160,7 +117773,7 @@ function scanForMissingBuildEnvRefs(cwd, existingKeys) {
|
|
|
117160
117773
|
continue;
|
|
117161
117774
|
let content;
|
|
117162
117775
|
try {
|
|
117163
|
-
content =
|
|
117776
|
+
content = readFileSync11(join23(cwd, rel), "utf8");
|
|
117164
117777
|
} catch {
|
|
117165
117778
|
continue;
|
|
117166
117779
|
}
|
|
@@ -117192,7 +117805,7 @@ function* walkDir(dir, base) {
|
|
|
117192
117805
|
for (const name of entries) {
|
|
117193
117806
|
if (SKIP_DIRS.has(name))
|
|
117194
117807
|
continue;
|
|
117195
|
-
const full =
|
|
117808
|
+
const full = join23(dir, name);
|
|
117196
117809
|
let st;
|
|
117197
117810
|
try {
|
|
117198
117811
|
st = statSync3(full);
|
|
@@ -117209,6 +117822,47 @@ function* walkDir(dir, base) {
|
|
|
117209
117822
|
|
|
117210
117823
|
// ../core/dist/commands/publish-api-error.js
|
|
117211
117824
|
init_dist();
|
|
117825
|
+
|
|
117826
|
+
// ../core/dist/commands/publish-rate-limit.js
|
|
117827
|
+
var RATE_LIMIT_CODES = new Set([
|
|
117828
|
+
"DEPLOY_RATE_LIMIT",
|
|
117829
|
+
"DEPLOY_RATE_LIMITED",
|
|
117830
|
+
"RATE_LIMIT_EXCEEDED"
|
|
117831
|
+
]);
|
|
117832
|
+
function matchRateLimit(err) {
|
|
117833
|
+
if (!RATE_LIMIT_CODES.has(err.code))
|
|
117834
|
+
return null;
|
|
117835
|
+
const wait = boundedSeconds(err.extra?.retryAfterSec);
|
|
117836
|
+
return {
|
|
117837
|
+
title: "Rate limit hit",
|
|
117838
|
+
explanation: err.message,
|
|
117839
|
+
suggestion: "Wait a few minutes and try again. If you need a higher cap, upgrade at https://percher.app/account/billing.",
|
|
117840
|
+
recovery: recoveryAsk({
|
|
117841
|
+
prompt: `Percher is rate-limiting deploys for this app${wait ? `; wait at least ${wait}s` : " — the window is up to an hour"}. This is a burst/hourly limit, not the daily deploy quota. Wait and retry, or upgrade the plan for a higher cap — which would you like?`,
|
|
117842
|
+
options: ["wait and retry", "upgrade", "cancel"],
|
|
117843
|
+
reasonCode: "quota_exceeded"
|
|
117844
|
+
}),
|
|
117845
|
+
summary: `Rate limit hit: ${err.message}`
|
|
117846
|
+
};
|
|
117847
|
+
}
|
|
117848
|
+
function matchConnectionRateLimit(err) {
|
|
117849
|
+
if (err.code !== "OAUTH_GRANT_RATE_LIMITED")
|
|
117850
|
+
return null;
|
|
117851
|
+
const wait = boundedSeconds(err.extra?.retryAfterSec) ?? 60;
|
|
117852
|
+
return {
|
|
117853
|
+
title: "Connection rate limit hit",
|
|
117854
|
+
explanation: err.message,
|
|
117855
|
+
suggestion: `Wait ${wait}s, then publish again. Nothing in the app needs to change.`,
|
|
117856
|
+
recovery: recoveryAsk({
|
|
117857
|
+
prompt: `Percher is limiting requests on this connection; wait at least ${wait}s, then publish again. Nothing in the app needs to change. Wait and retry, or cancel?`,
|
|
117858
|
+
options: ["wait and retry", "cancel"],
|
|
117859
|
+
reasonCode: "quota_exceeded"
|
|
117860
|
+
}),
|
|
117861
|
+
summary: `Connection rate limit hit. Retry in ${wait}s.`
|
|
117862
|
+
};
|
|
117863
|
+
}
|
|
117864
|
+
|
|
117865
|
+
// ../core/dist/commands/publish-api-error.js
|
|
117212
117866
|
var DEPLOY_GATE_CODES = new Set([
|
|
117213
117867
|
"RETRY_LIMIT_REACHED",
|
|
117214
117868
|
"REQUIRED_ENV_MISSING",
|
|
@@ -117228,6 +117882,9 @@ function classifyPublishApiError(err, input) {
|
|
|
117228
117882
|
const rateLimit = matchRateLimit(err);
|
|
117229
117883
|
if (rateLimit)
|
|
117230
117884
|
return buildResult(rateLimit, input);
|
|
117885
|
+
const connectionLimit = matchConnectionRateLimit(err);
|
|
117886
|
+
if (connectionLimit)
|
|
117887
|
+
return buildResult(connectionLimit, input);
|
|
117231
117888
|
const concurrent = matchConcurrentLimit(err);
|
|
117232
117889
|
if (concurrent)
|
|
117233
117890
|
return buildResult(concurrent, input);
|
|
@@ -117313,27 +117970,6 @@ function matchPlanLimit(err) {
|
|
|
117313
117970
|
summary: `Plan limit reached: ${err.message}`
|
|
117314
117971
|
};
|
|
117315
117972
|
}
|
|
117316
|
-
var RATE_LIMIT_CODES = new Set([
|
|
117317
|
-
"DEPLOY_RATE_LIMIT",
|
|
117318
|
-
"DEPLOY_RATE_LIMITED",
|
|
117319
|
-
"RATE_LIMIT_EXCEEDED"
|
|
117320
|
-
]);
|
|
117321
|
-
function matchRateLimit(err) {
|
|
117322
|
-
if (!RATE_LIMIT_CODES.has(err.code))
|
|
117323
|
-
return null;
|
|
117324
|
-
const wait = boundedSeconds(err.extra?.retryAfterSec);
|
|
117325
|
-
return {
|
|
117326
|
-
title: "Rate limit hit",
|
|
117327
|
-
explanation: err.message,
|
|
117328
|
-
suggestion: "Wait a few minutes and try again. If you need a higher cap, upgrade at https://percher.app/account/billing.",
|
|
117329
|
-
recovery: recoveryAsk({
|
|
117330
|
-
prompt: `Percher is rate-limiting deploys for this app${wait ? `; wait at least ${wait}s` : " — the window is up to an hour"}. This is a burst/hourly limit, not the daily deploy quota. Wait and retry, or upgrade the plan for a higher cap — which would you like?`,
|
|
117331
|
-
options: ["wait and retry", "upgrade", "cancel"],
|
|
117332
|
-
reasonCode: "quota_exceeded"
|
|
117333
|
-
}),
|
|
117334
|
-
summary: `Rate limit hit: ${err.message}`
|
|
117335
|
-
};
|
|
117336
|
-
}
|
|
117337
117973
|
var PLATFORM_DISK_CODES2 = new Set(["PLATFORM_DISK_LOW", "PLATFORM_DISK_UNKNOWN"]);
|
|
117338
117974
|
function matchPlatformDisk(err) {
|
|
117339
117975
|
if (!PLATFORM_DISK_CODES2.has(err.code))
|
|
@@ -117691,22 +118327,22 @@ function inFlightPublishResult(p, why) {
|
|
|
117691
118327
|
}
|
|
117692
118328
|
|
|
117693
118329
|
// ../core/dist/commands/publish-node.js
|
|
117694
|
-
import { existsSync as existsSync14, readFileSync as
|
|
117695
|
-
import { join as
|
|
118330
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
|
|
118331
|
+
import { join as join24 } from "node:path";
|
|
117696
118332
|
function resolveNodeVersion(cwd) {
|
|
117697
|
-
const nvmrc =
|
|
118333
|
+
const nvmrc = join24(cwd, ".nvmrc");
|
|
117698
118334
|
if (existsSync14(nvmrc)) {
|
|
117699
118335
|
try {
|
|
117700
|
-
const v =
|
|
118336
|
+
const v = readFileSync12(nvmrc, "utf8").trim();
|
|
117701
118337
|
if (v)
|
|
117702
118338
|
return { value: v, source: ".nvmrc" };
|
|
117703
118339
|
} catch {}
|
|
117704
118340
|
}
|
|
117705
|
-
const pkgPath =
|
|
118341
|
+
const pkgPath = join24(cwd, "package.json");
|
|
117706
118342
|
if (!existsSync14(pkgPath))
|
|
117707
118343
|
return null;
|
|
117708
118344
|
try {
|
|
117709
|
-
const pkg = JSON.parse(
|
|
118345
|
+
const pkg = JSON.parse(readFileSync12(pkgPath, "utf8"));
|
|
117710
118346
|
const engines = pkg?.engines?.node;
|
|
117711
118347
|
if (typeof engines === "string" && engines.length > 0) {
|
|
117712
118348
|
return { value: engines, source: "engines.node" };
|
|
@@ -117714,6 +118350,34 @@ function resolveNodeVersion(cwd) {
|
|
|
117714
118350
|
} catch {}
|
|
117715
118351
|
return { value: DEFAULT_NODE_VERSION_LABEL, source: "default" };
|
|
117716
118352
|
}
|
|
118353
|
+
function emitPreflight(ctx, config2, tarball) {
|
|
118354
|
+
const lines = [];
|
|
118355
|
+
const fw = config2.app.framework ?? (config2.app.runtime === "docker" ? "Dockerfile" : config2.app.runtime);
|
|
118356
|
+
lines.push(`Detected: ${fw} (runtime=${config2.app.runtime})`);
|
|
118357
|
+
if (config2.app.runtime === "bun") {
|
|
118358
|
+
lines.push("Bun: 1.x (default)");
|
|
118359
|
+
} else if (config2.app.runtime === "node") {
|
|
118360
|
+
const node = resolveNodeVersion(tarball.cwd);
|
|
118361
|
+
if (node) {
|
|
118362
|
+
lines.push(`Node: ${node.value} (${node.source})`);
|
|
118363
|
+
}
|
|
118364
|
+
}
|
|
118365
|
+
if (config2.build?.command) {
|
|
118366
|
+
lines.push(`Build: ${config2.build.command}`);
|
|
118367
|
+
}
|
|
118368
|
+
if (config2.web?.health) {
|
|
118369
|
+
lines.push(`Health: ${config2.web.health}`);
|
|
118370
|
+
}
|
|
118371
|
+
if (config2.web?.port) {
|
|
118372
|
+
lines.push(`Port: ${config2.web.port}`);
|
|
118373
|
+
}
|
|
118374
|
+
const sizeKb = (tarball.bytes / 1024).toFixed(1);
|
|
118375
|
+
lines.push(`Bundle: ${tarball.fileCount} files, ${sizeKb} KB`);
|
|
118376
|
+
lines.push(`Target: ${config2.app.name}`);
|
|
118377
|
+
for (const line of lines) {
|
|
118378
|
+
ctx.status(line);
|
|
118379
|
+
}
|
|
118380
|
+
}
|
|
117717
118381
|
|
|
117718
118382
|
// ../core/dist/commands/publish.js
|
|
117719
118383
|
var publishInputSchema = exports_external.object({
|
|
@@ -117729,7 +118393,7 @@ var publishInputSchema = exports_external.object({
|
|
|
117729
118393
|
var SUSPICIOUS_BYTES = 50 * 1024 * 1024;
|
|
117730
118394
|
var SUSPICIOUS_FILES = 1e4;
|
|
117731
118395
|
function tomlPathFor2(cwd) {
|
|
117732
|
-
return
|
|
118396
|
+
return join25(cwd, "percher.toml");
|
|
117733
118397
|
}
|
|
117734
118398
|
async function buildReplacedResult2(opts) {
|
|
117735
118399
|
const { ctx, app, deployment, tarball, cwd } = opts;
|
|
@@ -117885,7 +118549,7 @@ ${bullets}`,
|
|
|
117885
118549
|
bundle: { fileCount: 0, bytes: 0 }
|
|
117886
118550
|
};
|
|
117887
118551
|
}
|
|
117888
|
-
if (preParsedConfig && !input.dryRun && !existsSync15(
|
|
118552
|
+
if (preParsedConfig && !input.dryRun && !existsSync15(join25(ctx.cwd, "percher.toml"))) {
|
|
117889
118553
|
return {
|
|
117890
118554
|
status: "failed",
|
|
117891
118555
|
fileCount: 0,
|
|
@@ -118178,7 +118842,6 @@ async function finalizeDeploy(opts) {
|
|
|
118178
118842
|
intervalMs: 2000,
|
|
118179
118843
|
timeoutMs,
|
|
118180
118844
|
appName: app.name,
|
|
118181
|
-
terminal: ["live", "failed", "replaced"],
|
|
118182
118845
|
onTick: (d) => {
|
|
118183
118846
|
const elapsedMs = Date.now() - buildStart;
|
|
118184
118847
|
if (d.status !== lastStatus) {
|
|
@@ -118202,7 +118865,8 @@ async function finalizeDeploy(opts) {
|
|
|
118202
118865
|
}
|
|
118203
118866
|
});
|
|
118204
118867
|
} catch (err) {
|
|
118205
|
-
|
|
118868
|
+
const serverError = err instanceof PercherApiError && err.status >= 500 && err.status < 600;
|
|
118869
|
+
if (err instanceof DeployPollLostContactError || serverError)
|
|
118206
118870
|
return inFlightPublishResult(inFlight(), "lost_contact");
|
|
118207
118871
|
if (!timedOut)
|
|
118208
118872
|
throw err;
|
|
@@ -118234,8 +118898,8 @@ async function finalizeDeploy(opts) {
|
|
|
118234
118898
|
const buildMs = Date.now() - buildStart;
|
|
118235
118899
|
if (deployment.isCheck && deployment.checkPassed) {
|
|
118236
118900
|
const totalSeconds2 = (Date.now() - t0) / 1000;
|
|
118237
|
-
const
|
|
118238
|
-
ctx.status(
|
|
118901
|
+
const summary2 = `${app.name} check passed (${Math.round(totalSeconds2)}s) — would build and boot. The live app was not changed.`;
|
|
118902
|
+
ctx.status(summary2);
|
|
118239
118903
|
return {
|
|
118240
118904
|
status: "check_passed",
|
|
118241
118905
|
app,
|
|
@@ -118252,7 +118916,7 @@ async function finalizeDeploy(opts) {
|
|
|
118252
118916
|
missingBuildEnvKeys: missingBuildEnvKeys.length > 0 ? missingBuildEnvKeys : undefined,
|
|
118253
118917
|
traceId: deployment.id,
|
|
118254
118918
|
recovery: RECOVERY_NONE,
|
|
118255
|
-
summary,
|
|
118919
|
+
summary: summary2,
|
|
118256
118920
|
configPath: tomlPathFor2(ctx.cwd),
|
|
118257
118921
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
118258
118922
|
};
|
|
@@ -118420,6 +119084,7 @@ async function handleUnauthorized(ctx, config2, tarball, input) {
|
|
|
118420
119084
|
async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
118421
119085
|
const anonClient = new PercherClient({
|
|
118422
119086
|
apiUrl: ctx.client.apiUrl,
|
|
119087
|
+
token: null,
|
|
118423
119088
|
sessionId: ctx.client.sessionId
|
|
118424
119089
|
});
|
|
118425
119090
|
let created;
|
|
@@ -118432,7 +119097,8 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
118432
119097
|
created = await anonClient.anon.createAnonApp({
|
|
118433
119098
|
name: config2.app.name,
|
|
118434
119099
|
powChallengeId: ch.challengeId,
|
|
118435
|
-
powSolution: solution
|
|
119100
|
+
powSolution: solution,
|
|
119101
|
+
...ctx.syntheticFixture ? { testFixturePermit: ctx.syntheticFixture.permit } : {}
|
|
118436
119102
|
});
|
|
118437
119103
|
} catch (err) {
|
|
118438
119104
|
const httpStatus = err.status;
|
|
@@ -118473,13 +119139,15 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
118473
119139
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
118474
119140
|
};
|
|
118475
119141
|
}
|
|
118476
|
-
if (!
|
|
118477
|
-
|
|
118478
|
-
|
|
118479
|
-
|
|
118480
|
-
|
|
118481
|
-
|
|
118482
|
-
|
|
119142
|
+
if (!ctx.syntheticFixture) {
|
|
119143
|
+
if (!hasPersistedToken())
|
|
119144
|
+
saveConfig({ token: created.token });
|
|
119145
|
+
setAnonClaim({
|
|
119146
|
+
app: created.app.name,
|
|
119147
|
+
claimToken: created.claimToken,
|
|
119148
|
+
expiresAt: created.expiresAt
|
|
119149
|
+
});
|
|
119150
|
+
}
|
|
118483
119151
|
const newClient = new PercherClient({
|
|
118484
119152
|
apiUrl: ctx.client.apiUrl,
|
|
118485
119153
|
token: created.token,
|
|
@@ -118487,6 +119155,10 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
118487
119155
|
});
|
|
118488
119156
|
ctx.client = newClient;
|
|
118489
119157
|
ctx.setClient?.(newClient);
|
|
119158
|
+
if (ctx.syntheticFixture) {
|
|
119159
|
+
ctx.syntheticFixture.appId = created.app.id;
|
|
119160
|
+
ctx.syntheticFixture.created(created.app);
|
|
119161
|
+
}
|
|
118490
119162
|
config2.app.name = created.app.name;
|
|
118491
119163
|
const t0 = Date.now();
|
|
118492
119164
|
const freshTarball = await createTarball({ cwd: ctx.cwd, config: config2 });
|
|
@@ -118521,7 +119193,7 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
118521
119193
|
async function loadOrGenerate(ctx, preParsed) {
|
|
118522
119194
|
if (preParsed)
|
|
118523
119195
|
return structuredClone(preParsed);
|
|
118524
|
-
const tomlPath =
|
|
119196
|
+
const tomlPath = join25(ctx.cwd, "percher.toml");
|
|
118525
119197
|
if (!existsSync15(tomlPath)) {
|
|
118526
119198
|
ctx.status("No percher.toml found — detecting framework...");
|
|
118527
119199
|
const generated = await init(ctx);
|
|
@@ -118532,45 +119204,27 @@ async function loadOrGenerate(ctx, preParsed) {
|
|
|
118532
119204
|
async function ensureApp2(ctx, config2) {
|
|
118533
119205
|
try {
|
|
118534
119206
|
const app = await ctx.client.apps.get(config2.app.name);
|
|
119207
|
+
if (ctx.syntheticFixture && app.id !== ctx.syntheticFixture.appId) {
|
|
119208
|
+
throw new Error("Disposable fixture publishing requires a new app.");
|
|
119209
|
+
}
|
|
118535
119210
|
return { app, firstDeploy: false };
|
|
118536
119211
|
} catch (err) {
|
|
118537
119212
|
if (err.code === "APP_NOT_FOUND") {
|
|
118538
119213
|
const app = await ctx.client.apps.create({
|
|
118539
119214
|
name: config2.app.name,
|
|
118540
119215
|
runtime: config2.app.runtime,
|
|
118541
|
-
framework: config2.app.framework
|
|
119216
|
+
framework: config2.app.framework,
|
|
119217
|
+
...ctx.syntheticFixture ? { testFixturePermit: ctx.syntheticFixture.permit } : {}
|
|
118542
119218
|
});
|
|
119219
|
+
if (ctx.syntheticFixture) {
|
|
119220
|
+
ctx.syntheticFixture.appId = app.id;
|
|
119221
|
+
ctx.syntheticFixture.created(app);
|
|
119222
|
+
}
|
|
118543
119223
|
return { app, firstDeploy: true };
|
|
118544
119224
|
}
|
|
118545
119225
|
throw err;
|
|
118546
119226
|
}
|
|
118547
119227
|
}
|
|
118548
|
-
function emitPreflight(ctx, config2, tarball) {
|
|
118549
|
-
const lines = [];
|
|
118550
|
-
const fw = config2.app.framework ?? (config2.app.runtime === "docker" ? "Dockerfile" : config2.app.runtime);
|
|
118551
|
-
lines.push(`Detected: ${fw} (runtime=${config2.app.runtime})`);
|
|
118552
|
-
if (config2.app.runtime === "node" || config2.app.runtime === "bun") {
|
|
118553
|
-
const node = resolveNodeVersion(tarball.cwd);
|
|
118554
|
-
if (node) {
|
|
118555
|
-
lines.push(`Node: ${node.value} (${node.source})`);
|
|
118556
|
-
}
|
|
118557
|
-
}
|
|
118558
|
-
if (config2.build?.command) {
|
|
118559
|
-
lines.push(`Build: ${config2.build.command}`);
|
|
118560
|
-
}
|
|
118561
|
-
if (config2.web?.health) {
|
|
118562
|
-
lines.push(`Health: ${config2.web.health}`);
|
|
118563
|
-
}
|
|
118564
|
-
if (config2.web?.port) {
|
|
118565
|
-
lines.push(`Port: ${config2.web.port}`);
|
|
118566
|
-
}
|
|
118567
|
-
const sizeKb = (tarball.bytes / 1024).toFixed(1);
|
|
118568
|
-
lines.push(`Bundle: ${tarball.fileCount} files, ${sizeKb} KB`);
|
|
118569
|
-
lines.push(`Target: ${config2.app.name}`);
|
|
118570
|
-
for (const line of lines) {
|
|
118571
|
-
ctx.status(line);
|
|
118572
|
-
}
|
|
118573
|
-
}
|
|
118574
119228
|
// ../core/dist/commands/publish-from-repo.js
|
|
118575
119229
|
init_dist();
|
|
118576
119230
|
var publishFromRepoInputSchema = exports_external.object({
|
|
@@ -118601,7 +119255,7 @@ var publishInlineInputSchema = exports_external.object({
|
|
|
118601
119255
|
// ../core/dist/commands/push.js
|
|
118602
119256
|
init_dist();
|
|
118603
119257
|
import { existsSync as existsSync16 } from "node:fs";
|
|
118604
|
-
import { join as
|
|
119258
|
+
import { join as join26 } from "node:path";
|
|
118605
119259
|
var pushInputSchema = exports_external.object({
|
|
118606
119260
|
dryRun: exports_external.boolean().optional(),
|
|
118607
119261
|
force: exports_external.boolean().optional(),
|
|
@@ -118612,7 +119266,7 @@ var SUSPICIOUS_BYTES2 = 50 * 1024 * 1024;
|
|
|
118612
119266
|
var SUSPICIOUS_FILES2 = 1e4;
|
|
118613
119267
|
var PLACEHOLDER_PREFIXES = ["add-your-", "your-key-here"];
|
|
118614
119268
|
async function loadOrGenerate2(ctx) {
|
|
118615
|
-
const tomlPath =
|
|
119269
|
+
const tomlPath = join26(ctx.cwd, "percher.toml");
|
|
118616
119270
|
if (!existsSync16(tomlPath)) {
|
|
118617
119271
|
ctx.status("No percher.toml found — detecting framework...");
|
|
118618
119272
|
const result = await init(ctx);
|
|
@@ -118724,7 +119378,7 @@ async function push(ctx, input = {}, internals = {}) {
|
|
|
118724
119378
|
fileCount: tarball.fileCount,
|
|
118725
119379
|
recovery: RECOVERY_NONE,
|
|
118726
119380
|
summary: `Dry run for ${config2.app.name}: ${tarball.fileCount} files, ${(tarball.bytes / 1024).toFixed(1)} KB — no deploy performed.`,
|
|
118727
|
-
configPath:
|
|
119381
|
+
configPath: join26(ctx.cwd, "percher.toml"),
|
|
118728
119382
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
118729
119383
|
};
|
|
118730
119384
|
}
|
|
@@ -118876,12 +119530,13 @@ async function push(ctx, input = {}, internals = {}) {
|
|
|
118876
119530
|
});
|
|
118877
119531
|
}
|
|
118878
119532
|
});
|
|
119533
|
+
throwIfDeploymentReplaced(app.name, deployment);
|
|
118879
119534
|
if (deployment.status === "failed") {
|
|
118880
119535
|
const errorDetail = deployment.errorMessage ? `
|
|
118881
119536
|
${deployment.errorMessage}` : "";
|
|
118882
119537
|
const fromCode = classifyByErrorCode(deployment.errorCode, deployment.errorMessage ?? "");
|
|
118883
119538
|
const classified = fromCode ?? classifyError(deployment.errorMessage ?? "", "");
|
|
118884
|
-
const
|
|
119539
|
+
const recovery2 = classified ? recoveryFromErrorClass(classified.errorClass, {
|
|
118885
119540
|
missingEnvVars: classified.missingEnvVars,
|
|
118886
119541
|
deployId: deployment.id,
|
|
118887
119542
|
appName: app.name,
|
|
@@ -118895,7 +119550,7 @@ ${deployment.errorMessage}` : "";
|
|
|
118895
119550
|
throw new PercherCoreError(`Deployment failed (deploy ${deployment.id})${errorDetail}`, {
|
|
118896
119551
|
code: "push.deploy-failed",
|
|
118897
119552
|
hint: `Run \`percher deploys inspect ${deployment.id}\` to see the full build log and error. ${deployment.errorMessage ? "Fix the issue above and re-run." : "Look for the failing step in the build log."}`,
|
|
118898
|
-
recovery
|
|
119553
|
+
recovery: recovery2
|
|
118899
119554
|
});
|
|
118900
119555
|
}
|
|
118901
119556
|
const totalSec = ((Date.now() - startedAt) / 1000).toFixed(0);
|
|
@@ -118903,7 +119558,7 @@ ${deployment.errorMessage}` : "";
|
|
|
118903
119558
|
ctx.status(displayUrl ? `Preview at ${displayUrl} (${totalSec}s)` : `Live at ${deployment.url ?? app.url} (${totalSec}s)`);
|
|
118904
119559
|
const finalUrl = displayUrl ?? deployment.url ?? app.url;
|
|
118905
119560
|
const fwSuffix = config2.app.framework ? ` (${config2.app.framework}, ${totalSec}s)` : ` (${totalSec}s)`;
|
|
118906
|
-
const
|
|
119561
|
+
const summary2 = `${app.name} ${displayUrl ? "preview deployed" : "deployed"}${fwSuffix} → ${finalUrl}`;
|
|
118907
119562
|
return {
|
|
118908
119563
|
app,
|
|
118909
119564
|
deployment,
|
|
@@ -118911,8 +119566,8 @@ ${deployment.errorMessage}` : "";
|
|
|
118911
119566
|
bytes: tarball.bytes,
|
|
118912
119567
|
fileCount: tarball.fileCount,
|
|
118913
119568
|
recovery: RECOVERY_NONE,
|
|
118914
|
-
summary,
|
|
118915
|
-
configPath:
|
|
119569
|
+
summary: summary2,
|
|
119570
|
+
configPath: join26(ctx.cwd, "percher.toml"),
|
|
118916
119571
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
118917
119572
|
};
|
|
118918
119573
|
}
|
|
@@ -119183,9 +119838,11 @@ async function redeploy(ctx, input = {}) {
|
|
|
119183
119838
|
});
|
|
119184
119839
|
}
|
|
119185
119840
|
const totalSeconds = (Date.now() - t0) / 1000;
|
|
119841
|
+
if (deployment.status === "replaced")
|
|
119842
|
+
return replacedDeploymentResult(app, deployment);
|
|
119186
119843
|
const url2 = deployment.previewUrl ?? deployment.url ?? app.url;
|
|
119187
119844
|
if (deployment.status === "failed") {
|
|
119188
|
-
const { error: error48, recovery, summary } = await classifyDeploymentFailure({
|
|
119845
|
+
const { error: error48, recovery: recovery2, summary: summary2 } = await classifyDeploymentFailure({
|
|
119189
119846
|
ctx,
|
|
119190
119847
|
app,
|
|
119191
119848
|
deployment
|
|
@@ -119197,8 +119854,8 @@ async function redeploy(ctx, input = {}) {
|
|
|
119197
119854
|
fileCount: 0,
|
|
119198
119855
|
bytes: 0,
|
|
119199
119856
|
error: error48,
|
|
119200
|
-
recovery,
|
|
119201
|
-
summary,
|
|
119857
|
+
recovery: recovery2,
|
|
119858
|
+
summary: summary2,
|
|
119202
119859
|
configPath: "",
|
|
119203
119860
|
bundle: { fileCount: 0, bytes: 0 }
|
|
119204
119861
|
};
|
|
@@ -119241,8 +119898,8 @@ function failureResult(error48) {
|
|
|
119241
119898
|
};
|
|
119242
119899
|
}
|
|
119243
119900
|
// ../core/dist/commands/rename.js
|
|
119244
|
-
import { existsSync as existsSync17, readFileSync as
|
|
119245
|
-
import { join as
|
|
119901
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "node:fs";
|
|
119902
|
+
import { join as join27 } from "node:path";
|
|
119246
119903
|
var renameInputSchema = exports_external.object({
|
|
119247
119904
|
app: exports_external.string().optional(),
|
|
119248
119905
|
name: exports_external.string().min(3).max(40)
|
|
@@ -119262,17 +119919,17 @@ async function rename3(ctx, input) {
|
|
|
119262
119919
|
};
|
|
119263
119920
|
}
|
|
119264
119921
|
function updateLocalTomlName(cwd, oldName, newName) {
|
|
119265
|
-
const p =
|
|
119922
|
+
const p = join27(cwd, "percher.toml");
|
|
119266
119923
|
if (!existsSync17(p))
|
|
119267
119924
|
return false;
|
|
119268
119925
|
try {
|
|
119269
|
-
const src =
|
|
119926
|
+
const src = readFileSync13(p, "utf8");
|
|
119270
119927
|
if (parse5(src).app.name !== oldName)
|
|
119271
119928
|
return false;
|
|
119272
119929
|
const next = src.replace(new RegExp(`(name\\s*=\\s*")${oldName}(")`), `$1${newName}$2`);
|
|
119273
119930
|
if (next === src || parse5(next).app.name !== newName)
|
|
119274
119931
|
return false;
|
|
119275
|
-
|
|
119932
|
+
writeFileSync10(p, next);
|
|
119276
119933
|
return true;
|
|
119277
119934
|
} catch {
|
|
119278
119935
|
return false;
|
|
@@ -119281,9 +119938,9 @@ function updateLocalTomlName(cwd, oldName, newName) {
|
|
|
119281
119938
|
// ../core/dist/commands/reproduce.js
|
|
119282
119939
|
init_dist();
|
|
119283
119940
|
var import_cross_spawn3 = __toESM(require_cross_spawn(), 1);
|
|
119284
|
-
import { mkdtempSync, writeFileSync as
|
|
119941
|
+
import { mkdtempSync, writeFileSync as writeFileSync11 } from "node:fs";
|
|
119285
119942
|
import { tmpdir } from "node:os";
|
|
119286
|
-
import { join as
|
|
119943
|
+
import { join as join28 } from "node:path";
|
|
119287
119944
|
function runProcessExit(cmd, args, opts = {}) {
|
|
119288
119945
|
return new Promise((resolve11, reject) => {
|
|
119289
119946
|
const child = import_cross_spawn3.default(cmd, args, {
|
|
@@ -119377,9 +120034,9 @@ async function reproduce(ctx, input) {
|
|
|
119377
120034
|
const envMap = await ctx.client.env.list(app.id);
|
|
119378
120035
|
currentAppEnvKeys = Object.keys(envMap).sort();
|
|
119379
120036
|
} catch {}
|
|
119380
|
-
const tmpDir = mkdtempSync(
|
|
119381
|
-
const tarballPath =
|
|
119382
|
-
|
|
120037
|
+
const tmpDir = mkdtempSync(join28(tmpdir(), `percher-reproduce-${input.deployId}-`));
|
|
120038
|
+
const tarballPath = join28(tmpDir, "source.tar.gz");
|
|
120039
|
+
writeFileSync11(tarballPath, bytes);
|
|
119383
120040
|
let extracted = false;
|
|
119384
120041
|
try {
|
|
119385
120042
|
extracted = await runProcessExit("tar", ["-xzf", tarballPath, "-C", tmpDir]) === 0;
|
|
@@ -119596,19 +120253,19 @@ function versionAge(iso, now = Date.now()) {
|
|
|
119596
120253
|
return `${d}d ago`;
|
|
119597
120254
|
return `${Math.floor(d / 30)}mo ago`;
|
|
119598
120255
|
}
|
|
119599
|
-
function rollbackTargetMarker(
|
|
119600
|
-
if (isLive || !
|
|
120256
|
+
function rollbackTargetMarker(target2, isLive) {
|
|
120257
|
+
if (isLive || !target2)
|
|
119601
120258
|
return "";
|
|
119602
|
-
if (
|
|
120259
|
+
if (target2.mode === "rebuild")
|
|
119603
120260
|
return " [rebuild required]";
|
|
119604
|
-
if (
|
|
120261
|
+
if (target2.mode === "none")
|
|
119605
120262
|
return " [not a rollback target]";
|
|
119606
120263
|
return "";
|
|
119607
120264
|
}
|
|
119608
|
-
function rollbackTargetDetail(
|
|
119609
|
-
if (isLive || !
|
|
120265
|
+
function rollbackTargetDetail(target2, isLive) {
|
|
120266
|
+
if (isLive || !target2 || target2.mode === "in-window")
|
|
119610
120267
|
return [];
|
|
119611
|
-
const explanation =
|
|
120268
|
+
const explanation = target2.explanation?.trim();
|
|
119612
120269
|
return explanation ? [` ${explanation}`] : [];
|
|
119613
120270
|
}
|
|
119614
120271
|
async function writeLine(ctx, line) {
|
|
@@ -119643,14 +120300,15 @@ async function resolveCommitSha(ctx, name, input) {
|
|
|
119643
120300
|
const pick2 = versions2.slice(0, BARE_PICK_LIMIT);
|
|
119644
120301
|
if (!ctx.stdinIsInteractive) {
|
|
119645
120302
|
const appFlag = ` --app ${name}`;
|
|
119646
|
-
const lines = pick2.flatMap((v
|
|
120303
|
+
const lines = pick2.flatMap((v) => {
|
|
120304
|
+
const isLive = v.rollbackTarget?.reason === "ALREADY_LIVE";
|
|
119647
120305
|
const note = v.message.split(`
|
|
119648
120306
|
`)[0]?.trim() || "Published";
|
|
119649
|
-
const marker = rollbackTargetMarker(v.rollbackTarget,
|
|
119650
|
-
const detail = rollbackTargetDetail(v.rollbackTarget,
|
|
120307
|
+
const marker = isLive ? " (live now)" : rollbackTargetMarker(v.rollbackTarget, false);
|
|
120308
|
+
const detail = rollbackTargetDetail(v.rollbackTarget, isLive);
|
|
119651
120309
|
const git = v.remoteSha ? ` git ${v.remoteSha.slice(0, 7)}` : "";
|
|
119652
120310
|
const suffix = ` # ${note}${git} (${versionAge(v.timestamp)})${marker}`;
|
|
119653
|
-
if (v.rollbackTarget?.mode === "none"
|
|
120311
|
+
if (v.rollbackTarget?.mode === "none") {
|
|
119654
120312
|
return [` ${v.sha}${suffix}`, ...detail];
|
|
119655
120313
|
}
|
|
119656
120314
|
const rebuildFlag = v.rollbackTarget?.mode === "rebuild" ? " --rebuild" : "";
|
|
@@ -119668,10 +120326,11 @@ ${lines.join(`
|
|
|
119668
120326
|
const note = v.message.split(`
|
|
119669
120327
|
`)[0]?.trim() || "Published";
|
|
119670
120328
|
const git = v.remoteSha ? ` git ${v.remoteSha.slice(0, 7)}` : "";
|
|
119671
|
-
const
|
|
119672
|
-
const
|
|
120329
|
+
const isLive = v.rollbackTarget?.reason === "ALREADY_LIVE";
|
|
120330
|
+
const live = isLive ? " (live now)" : "";
|
|
120331
|
+
const marker = rollbackTargetMarker(v.rollbackTarget, isLive);
|
|
119673
120332
|
await writeLine(ctx, ` ${i + 1}. ${v.sha.slice(0, 10)} ${versionAge(v.timestamp)} ${note}${git}${live}${marker}`);
|
|
119674
|
-
for (const detail of rollbackTargetDetail(v.rollbackTarget,
|
|
120333
|
+
for (const detail of rollbackTargetDetail(v.rollbackTarget, isLive)) {
|
|
119675
120334
|
await writeLine(ctx, detail);
|
|
119676
120335
|
}
|
|
119677
120336
|
}
|
|
@@ -119724,6 +120383,7 @@ async function rollback(ctx, input, internals = {}) {
|
|
|
119724
120383
|
});
|
|
119725
120384
|
}
|
|
119726
120385
|
});
|
|
120386
|
+
throwIfDeploymentReplaced(name, deployment);
|
|
119727
120387
|
if (deployment.status === "failed") {
|
|
119728
120388
|
throw new PercherCoreError("Rollback failed", {
|
|
119729
120389
|
code: "push.deploy-failed",
|
|
@@ -119734,7 +120394,7 @@ async function rollback(ctx, input, internals = {}) {
|
|
|
119734
120394
|
}
|
|
119735
120395
|
// ../core/dist/commands/sharing.js
|
|
119736
120396
|
var ShareRoleSchema = exports_external.enum(["viewer", "admin"]);
|
|
119737
|
-
function
|
|
120397
|
+
function resolveApp5(ctx, app) {
|
|
119738
120398
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
119739
120399
|
if (!name) {
|
|
119740
120400
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -119762,19 +120422,19 @@ var shareRevokeInputSchema = exports_external.object({
|
|
|
119762
120422
|
shareId: exports_external.string().min(1, "shareId is required")
|
|
119763
120423
|
});
|
|
119764
120424
|
async function shareList(ctx, input = {}) {
|
|
119765
|
-
const appRef2 =
|
|
120425
|
+
const appRef2 = resolveApp5(ctx, input.app);
|
|
119766
120426
|
return ctx.client.sharing.list(appRef2);
|
|
119767
120427
|
}
|
|
119768
120428
|
async function shareInvite(ctx, input) {
|
|
119769
|
-
const appRef2 =
|
|
120429
|
+
const appRef2 = resolveApp5(ctx, input.app);
|
|
119770
120430
|
return ctx.client.sharing.create(appRef2, { email: input.email, role: input.role });
|
|
119771
120431
|
}
|
|
119772
120432
|
async function shareSetRole(ctx, input) {
|
|
119773
|
-
const appRef2 =
|
|
120433
|
+
const appRef2 = resolveApp5(ctx, input.app);
|
|
119774
120434
|
return ctx.client.sharing.setRole(appRef2, input.shareId, input.role);
|
|
119775
120435
|
}
|
|
119776
120436
|
async function shareRevoke(ctx, input) {
|
|
119777
|
-
const appRef2 =
|
|
120437
|
+
const appRef2 = resolveApp5(ctx, input.app);
|
|
119778
120438
|
await ctx.client.sharing.revoke(appRef2, input.shareId);
|
|
119779
120439
|
}
|
|
119780
120440
|
var invitesListInputSchema = exports_external.object({});
|
|
@@ -119882,7 +120542,7 @@ async function tokenRevoke(ctx, input) {
|
|
|
119882
120542
|
await ctx.client.account.revokeToken(input.id);
|
|
119883
120543
|
}
|
|
119884
120544
|
// ../core/dist/commands/transfers.js
|
|
119885
|
-
function
|
|
120545
|
+
function resolveApp6(ctx, app) {
|
|
119886
120546
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
119887
120547
|
if (!name) {
|
|
119888
120548
|
throw new PercherCoreError("No app specified and no percher.toml found", {
|
|
@@ -119904,15 +120564,15 @@ var transferListForAppInputSchema = exports_external.object({
|
|
|
119904
120564
|
app: exports_external.string().optional()
|
|
119905
120565
|
});
|
|
119906
120566
|
async function transferInitiate(ctx, input) {
|
|
119907
|
-
const appRef2 =
|
|
120567
|
+
const appRef2 = resolveApp6(ctx, input.app);
|
|
119908
120568
|
return ctx.client.transfers.initiate(appRef2, { email: input.email });
|
|
119909
120569
|
}
|
|
119910
120570
|
async function transferCancel(ctx, input) {
|
|
119911
|
-
const appRef2 =
|
|
120571
|
+
const appRef2 = resolveApp6(ctx, input.app);
|
|
119912
120572
|
await ctx.client.transfers.cancel(appRef2, input.transferId);
|
|
119913
120573
|
}
|
|
119914
120574
|
async function transferListForApp(ctx, input = {}) {
|
|
119915
|
-
const appRef2 =
|
|
120575
|
+
const appRef2 = resolveApp6(ctx, input.app);
|
|
119916
120576
|
return ctx.client.transfers.listForApp(appRef2);
|
|
119917
120577
|
}
|
|
119918
120578
|
var transfersIncomingInputSchema = exports_external.object({});
|
|
@@ -119977,6 +120637,7 @@ var SOURCE_EXTS2 = new Set([
|
|
|
119977
120637
|
".py"
|
|
119978
120638
|
]);
|
|
119979
120639
|
var DEFAULT_MAX_FILE_BYTES = 1024 * 1024;
|
|
120640
|
+
var IMPORT_META_CONSTANTS = new Set(["DEV", "PROD", "MODE", "BASE_URL", "SSR"]);
|
|
119980
120641
|
// ../core/dist/plans.js
|
|
119981
120642
|
var PB_INITIAL_FOOTPRINT_MB = 256;
|
|
119982
120643
|
var EGRESS_GB_PER_MONTH = {
|
|
@@ -120183,6 +120844,15 @@ async function writeLine2(ctx, line) {
|
|
|
120183
120844
|
writer.releaseLock();
|
|
120184
120845
|
}
|
|
120185
120846
|
}
|
|
120847
|
+
async function writeErrLine(ctx, line) {
|
|
120848
|
+
const writer = ctx.stderr.getWriter();
|
|
120849
|
+
try {
|
|
120850
|
+
await writer.write(new TextEncoder().encode(`${line}
|
|
120851
|
+
`));
|
|
120852
|
+
} finally {
|
|
120853
|
+
writer.releaseLock();
|
|
120854
|
+
}
|
|
120855
|
+
}
|
|
120186
120856
|
async function writeUnknownCommand(ctx, name) {
|
|
120187
120857
|
const writer = ctx.stderr.getWriter();
|
|
120188
120858
|
try {
|
|
@@ -120750,8 +121420,8 @@ function registerAdminCommands(cli, ctx) {
|
|
|
120750
121420
|
if (topology?.topologyReady !== true) {
|
|
120751
121421
|
await writeLine2(ctx, `${import_picocolors3.default.red("✗")} tenant topology audit is red or unavailable — no launch all-clear.`);
|
|
120752
121422
|
for (const finding of topology?.findings ?? []) {
|
|
120753
|
-
const
|
|
120754
|
-
await writeLine2(ctx, ` ${import_picocolors3.default.red("✗")} ${finding.code} [${
|
|
121423
|
+
const target2 = finding.network ?? finding.containerId ?? finding.appId ?? "fleet";
|
|
121424
|
+
await writeLine2(ctx, ` ${import_picocolors3.default.red("✗")} ${finding.code} [${target2}] — ${finding.detail}`);
|
|
120755
121425
|
}
|
|
120756
121426
|
}
|
|
120757
121427
|
if (options.app || options.appId) {
|
|
@@ -120765,8 +121435,8 @@ function registerAdminCommands(cli, ctx) {
|
|
|
120765
121435
|
await writeLine2(ctx, `${import_picocolors3.default.yellow("!")} drift: ${missing} missing route(s), ${hostDrift} missing host(s), ${extra} extra route(s)`);
|
|
120766
121436
|
for (const d of drift) {
|
|
120767
121437
|
const label = d.kind === "missing_route" ? import_picocolors3.default.red("MISSING") : d.kind === "missing_host" ? import_picocolors3.default.yellow("HOST_DRIFT") : import_picocolors3.default.dim("EXTRA");
|
|
120768
|
-
const
|
|
120769
|
-
await writeLine2(ctx, ` ${label} ${
|
|
121438
|
+
const target2 = d.appName ? `[${d.appName}] ` : "";
|
|
121439
|
+
await writeLine2(ctx, ` ${label} ${target2}${d.routeId} (${d.routeType}) — ${d.hosts.join(", ")}`);
|
|
120770
121440
|
}
|
|
120771
121441
|
}
|
|
120772
121442
|
await writeLine2(ctx, import_picocolors3.default.dim(`Repair: percher admin reconcile-routes${options.app ? ` --app ${options.app}` : ""}`));
|
|
@@ -120842,8 +121512,8 @@ async function printList(ctx, title, rows) {
|
|
|
120842
121512
|
|
|
120843
121513
|
// src/commands/apps.ts
|
|
120844
121514
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
120845
|
-
function assertNever2(status2,
|
|
120846
|
-
throw new Error(`Unhandled publish status: ${JSON.stringify(status2)}${
|
|
121515
|
+
function assertNever2(status2, summary2) {
|
|
121516
|
+
throw new Error(`Unhandled publish status: ${JSON.stringify(status2)}${summary2 ? ` (${summary2})` : ""}`);
|
|
120847
121517
|
}
|
|
120848
121518
|
async function handlePublishResult(ctx, result, options = {}) {
|
|
120849
121519
|
switch (result.status) {
|
|
@@ -121082,6 +121752,10 @@ function registerAppsCommands(cli, ctx) {
|
|
|
121082
121752
|
deployId,
|
|
121083
121753
|
noCache: options.cache === false
|
|
121084
121754
|
});
|
|
121755
|
+
if (result.status === "replaced") {
|
|
121756
|
+
await handlePublishResult(ctx, result);
|
|
121757
|
+
throw new SilentExitError;
|
|
121758
|
+
}
|
|
121085
121759
|
if (result.status === "needs_login") {
|
|
121086
121760
|
await writeLine2(ctx, `${import_picocolors5.default.red("✗")} Not logged in. Run: percher login`);
|
|
121087
121761
|
throw new SilentExitError;
|
|
@@ -121399,6 +122073,154 @@ function registerAuthCommands(cli, ctx) {
|
|
|
121399
122073
|
|
|
121400
122074
|
// src/commands/data.ts
|
|
121401
122075
|
var import_picocolors7 = __toESM(require_picocolors(), 1);
|
|
122076
|
+
|
|
122077
|
+
// src/commands/data-records.ts
|
|
122078
|
+
var DATA_RECORD_SUBCOMMANDS = new Set([
|
|
122079
|
+
"schema",
|
|
122080
|
+
"query",
|
|
122081
|
+
"get",
|
|
122082
|
+
"create",
|
|
122083
|
+
"update",
|
|
122084
|
+
"delete"
|
|
122085
|
+
]);
|
|
122086
|
+
|
|
122087
|
+
class DataArgumentError extends PercherCoreError {
|
|
122088
|
+
constructor(message) {
|
|
122089
|
+
super(message, { code: "data.missing-argument" });
|
|
122090
|
+
}
|
|
122091
|
+
}
|
|
122092
|
+
function cacKey(name) {
|
|
122093
|
+
return name.replaceAll(/([a-z])-([a-z])/g, (_, a, b) => a + b.toUpperCase());
|
|
122094
|
+
}
|
|
122095
|
+
function textOption(argv, options, key, flag) {
|
|
122096
|
+
const parsed = options[key];
|
|
122097
|
+
if (parsed === undefined)
|
|
122098
|
+
return;
|
|
122099
|
+
if (typeof parsed === "string")
|
|
122100
|
+
return parsed;
|
|
122101
|
+
if (typeof parsed !== "number") {
|
|
122102
|
+
throw new DataArgumentError(`${flag} needs exactly one value`);
|
|
122103
|
+
}
|
|
122104
|
+
const end = argv.includes("--") ? argv.indexOf("--") : argv.length;
|
|
122105
|
+
let raw;
|
|
122106
|
+
for (let i = 0;i < end; i++) {
|
|
122107
|
+
const m = /^--([^=]+)(?:=(.*))?$/s.exec(argv[i] ?? "");
|
|
122108
|
+
if (!m || cacKey(m[1] ?? "") !== key)
|
|
122109
|
+
continue;
|
|
122110
|
+
raw = m[2] ?? argv[i + 1];
|
|
122111
|
+
}
|
|
122112
|
+
if (raw === undefined || Number(raw) !== parsed) {
|
|
122113
|
+
throw new DataArgumentError(`${flag} could not be read as typed`);
|
|
122114
|
+
}
|
|
122115
|
+
return raw;
|
|
122116
|
+
}
|
|
122117
|
+
function intOption(options, key, flag) {
|
|
122118
|
+
const parsed = options[key];
|
|
122119
|
+
if (parsed === undefined)
|
|
122120
|
+
return;
|
|
122121
|
+
if (typeof parsed === "number")
|
|
122122
|
+
return parsed;
|
|
122123
|
+
if (typeof parsed === "string")
|
|
122124
|
+
return Number(parsed);
|
|
122125
|
+
throw new DataArgumentError(`${flag} needs exactly one value`);
|
|
122126
|
+
}
|
|
122127
|
+
function recordPositionals(rest, options) {
|
|
122128
|
+
const after = Array.isArray(options["--"]) ? options["--"] : [];
|
|
122129
|
+
const all = [...rest, ...after];
|
|
122130
|
+
if (!all.every((v) => typeof v === "string")) {
|
|
122131
|
+
throw new DataArgumentError("Could not read the collection or record id as typed; put boolean flags after them");
|
|
122132
|
+
}
|
|
122133
|
+
return all;
|
|
122134
|
+
}
|
|
122135
|
+
function recordData2(value) {
|
|
122136
|
+
let parsed;
|
|
122137
|
+
try {
|
|
122138
|
+
parsed = JSON.parse(value ?? "");
|
|
122139
|
+
} catch {
|
|
122140
|
+
parsed = undefined;
|
|
122141
|
+
}
|
|
122142
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
122143
|
+
throw new PercherCoreError("--data must be a JSON object of field values", {
|
|
122144
|
+
code: "data.invalid-json",
|
|
122145
|
+
hint: `Example: --data '{"title":"Buy milk","done":false}'`
|
|
122146
|
+
});
|
|
122147
|
+
}
|
|
122148
|
+
return parsed;
|
|
122149
|
+
}
|
|
122150
|
+
function missing(usage) {
|
|
122151
|
+
throw new PercherCoreError(`Missing arguments. Usage: percher ${usage}`, {
|
|
122152
|
+
code: "data.missing-argument"
|
|
122153
|
+
});
|
|
122154
|
+
}
|
|
122155
|
+
async function runDataRecordCommand(ctx, argv, sub, rest, options) {
|
|
122156
|
+
const [collection, id] = recordPositionals(rest, options);
|
|
122157
|
+
const text = (key, flag) => textOption(argv, options, key, flag);
|
|
122158
|
+
const app = text("app", "--app");
|
|
122159
|
+
let result;
|
|
122160
|
+
switch (sub) {
|
|
122161
|
+
case "schema":
|
|
122162
|
+
result = await dataSchema2(ctx, dataSchemaInputSchema.parse({ app }));
|
|
122163
|
+
break;
|
|
122164
|
+
case "query":
|
|
122165
|
+
if (!collection)
|
|
122166
|
+
missing("data query <collection> [--filter …] [--app <name>]");
|
|
122167
|
+
result = await dataQuery(ctx, dataQueryInputSchema.parse({
|
|
122168
|
+
app,
|
|
122169
|
+
collection,
|
|
122170
|
+
filter: text("filter", "--filter"),
|
|
122171
|
+
sort: text("sort", "--sort"),
|
|
122172
|
+
page: intOption(options, "page", "--page"),
|
|
122173
|
+
perPage: intOption(options, "perPage", "--per-page"),
|
|
122174
|
+
fields: text("fields", "--fields")
|
|
122175
|
+
}));
|
|
122176
|
+
break;
|
|
122177
|
+
case "get":
|
|
122178
|
+
if (!collection || !id)
|
|
122179
|
+
missing("data get <collection> <id> [--app <name>]");
|
|
122180
|
+
result = await dataGet(ctx, dataGetInputSchema.parse({ app, collection, id }));
|
|
122181
|
+
break;
|
|
122182
|
+
case "create":
|
|
122183
|
+
if (!collection)
|
|
122184
|
+
missing("data create <collection> --data '<json>' [--id <id>]");
|
|
122185
|
+
result = await dataCreate(ctx, dataCreateInputSchema.parse({
|
|
122186
|
+
app,
|
|
122187
|
+
collection,
|
|
122188
|
+
data: recordData2(text("data", "--data")),
|
|
122189
|
+
id: text("id", "--id")
|
|
122190
|
+
}));
|
|
122191
|
+
break;
|
|
122192
|
+
case "update":
|
|
122193
|
+
if (!collection || !id)
|
|
122194
|
+
missing("data update <collection> <id> --data '<json>'");
|
|
122195
|
+
result = await dataUpdate(ctx, dataUpdateInputSchema.parse({
|
|
122196
|
+
app,
|
|
122197
|
+
collection,
|
|
122198
|
+
id,
|
|
122199
|
+
data: recordData2(text("data", "--data")),
|
|
122200
|
+
ifUpdated: text("ifUpdated", "--if-updated")
|
|
122201
|
+
}));
|
|
122202
|
+
break;
|
|
122203
|
+
case "delete":
|
|
122204
|
+
if (!collection || !id)
|
|
122205
|
+
missing("data delete <collection> <id> [--app <name>]");
|
|
122206
|
+
result = await dataDelete(ctx, dataDeleteInputSchema.parse({ app, collection, id }));
|
|
122207
|
+
break;
|
|
122208
|
+
default:
|
|
122209
|
+
return;
|
|
122210
|
+
}
|
|
122211
|
+
await writeLine2(ctx, JSON.stringify(result, null, 2));
|
|
122212
|
+
}
|
|
122213
|
+
function registerDataRecordHelp(cli) {
|
|
122214
|
+
const none = async () => {};
|
|
122215
|
+
cli.command("data schema", "List the collections and fields the data tools can use").action(none);
|
|
122216
|
+
cli.command("data query <collection>", "Query records (--filter, --sort, --page, --per-page, --fields)").action(none);
|
|
122217
|
+
cli.command("data get <collection> <id>", "Get one record").action(none);
|
|
122218
|
+
cli.command("data create <collection>", "Create a record from --data '<json>' (optional --id)").action(none);
|
|
122219
|
+
cli.command("data update <collection> <id>", "Change fields from --data '<json>' (optional --if-updated)").action(none);
|
|
122220
|
+
cli.command("data delete <collection> <id>", "Delete one record").action(none);
|
|
122221
|
+
}
|
|
122222
|
+
|
|
122223
|
+
// src/commands/data.ts
|
|
121402
122224
|
var DATA_VALUE_FLAGS = new Set([
|
|
121403
122225
|
"--out",
|
|
121404
122226
|
"--app",
|
|
@@ -121407,7 +122229,11 @@ var DATA_VALUE_FLAGS = new Set([
|
|
|
121407
122229
|
"--client-secret"
|
|
121408
122230
|
]);
|
|
121409
122231
|
function registerDataCommands(cli, ctx, argv) {
|
|
121410
|
-
cli.command("data [app] [...rest]", "Show app data status and collections").option("--json", "Output as JSON").option("--reveal", "(reset-superuser only) also print the plaintext password once").option("--out <path>", "(export only) Output file (default: ./<app>-pb-<timestamp>.tar.gz)").option("--provider <name>", "(oauth only) OAuth provider (default: google)").option("--app <name>", "
|
|
122232
|
+
cli.command("data [app] [...rest]", "Show app data status and collections").option("--json", "Output as JSON").option("--reveal", "(reset-superuser only) also print the plaintext password once").option("--out <path>", "(export only) Output file (default: ./<app>-pb-<timestamp>.tar.gz)").option("--provider <name>", "(oauth only) OAuth provider (default: google)").option("--app <name>", "Target app (default: read percher.toml); names an app called like a subcommand, e.g. `data --app get`").option("--client-id <id>", "(oauth only) OAuth client id").option("--client-secret <secret>", "(oauth only) OAuth client secret (a command-line value lands in shell history)").option("--remove", "(oauth only) remove the provider instead of setting it").option("--filter <expr>", "(query only) filter over the collection's fields").option("--sort <fields>", "(query only) comma-separated fields, - for descending (write --sort=-field)").option("--page <n>", "(query only) page number").option("--per-page <n>", "(query only) records per page (max 100)").option("--fields <fields>", "(query only) comma-separated fields to return").option("--data <json>", "(create, update) field values as a JSON object").option("--id <id>", "(create only) id for the new record").option("--if-updated <timestamp>", "(update only) refuse if the record changed since").action(async (app, _rest, options) => {
|
|
122233
|
+
if (app !== undefined && DATA_RECORD_SUBCOMMANDS.has(app)) {
|
|
122234
|
+
await runDataRecordCommand(ctx, argv, app, _rest, options);
|
|
122235
|
+
return;
|
|
122236
|
+
}
|
|
121411
122237
|
if (app === "reset-superuser") {
|
|
121412
122238
|
const idx = argv.indexOf("reset-superuser");
|
|
121413
122239
|
const realApp = idx >= 0 ? firstNonFlagAfter(argv, idx) : undefined;
|
|
@@ -121458,7 +122284,7 @@ function registerDataCommands(cli, ctx, argv) {
|
|
|
121458
122284
|
}
|
|
121459
122285
|
return;
|
|
121460
122286
|
}
|
|
121461
|
-
const result = await data(ctx, { app, json: options.json });
|
|
122287
|
+
const result = await data(ctx, { app: app ?? options.app, json: options.json });
|
|
121462
122288
|
if (options.json) {
|
|
121463
122289
|
await writeLine2(ctx, JSON.stringify(result, null, 2));
|
|
121464
122290
|
} else {
|
|
@@ -121483,6 +122309,7 @@ function registerDataCommands(cli, ctx, argv) {
|
|
|
121483
122309
|
}
|
|
121484
122310
|
}
|
|
121485
122311
|
});
|
|
122312
|
+
registerDataRecordHelp(cli);
|
|
121486
122313
|
cli.command("data reset-superuser [app]", "Reset PocketBase superuser and inject new credentials").option("--reveal", "Also print the plaintext password once (default: hidden)").action(async (app, options) => {
|
|
121487
122314
|
const result = await resetSuperuser(ctx, { app, reveal: options.reveal });
|
|
121488
122315
|
await printSuperuserResetResult(ctx, result);
|
|
@@ -121578,6 +122405,7 @@ function registerDeploysCommands(cli, ctx, argv) {
|
|
|
121578
122405
|
rebuild: Boolean(options.rebuild)
|
|
121579
122406
|
});
|
|
121580
122407
|
await writeLine2(ctx, `${import_picocolors8.default.green("✓")} rolled back to ${result.rolledBackTo.slice(0, 10)} (status: ${result.status})`);
|
|
122408
|
+
await writeLine2(ctx, "Env vars are not rolled back; the current values stay.");
|
|
121581
122409
|
});
|
|
121582
122410
|
cli.command("reproduce <deployId>", "Download a deploy's source and reproduce the build locally").option("--app <name>", "App name (defaults to percher.toml app.name)").action(async (deployId, options) => {
|
|
121583
122411
|
const result = await reproduce(ctx, {
|
|
@@ -121656,6 +122484,8 @@ function registerDeploysCommands(cli, ctx, argv) {
|
|
|
121656
122484
|
for (const v of list) {
|
|
121657
122485
|
const message = v.message.split(`
|
|
121658
122486
|
`)[0]?.trim() ?? "";
|
|
122487
|
+
const note = Array.from((v.note ?? "").replace(/[\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}]/gu, " ").replace(/\s+/g, " ").trim());
|
|
122488
|
+
const noteLabel = note.length > 80 ? `${note.slice(0, 79).join("")}…` : note.join("");
|
|
121659
122489
|
const channelLabels = {
|
|
121660
122490
|
cli: "CLI",
|
|
121661
122491
|
mcp: "MCP",
|
|
@@ -121666,11 +122496,11 @@ function registerDeploysCommands(cli, ctx, argv) {
|
|
|
121666
122496
|
const label = v.channel ? channelLabels[v.channel] ?? v.channel : null;
|
|
121667
122497
|
const git = v.remoteSha ? ` · git ${v.remoteSha.slice(0, 7)}` : "";
|
|
121668
122498
|
const suffix = `${label ? ` · via ${label}` : ""}${git}`;
|
|
121669
|
-
const
|
|
121670
|
-
const marker =
|
|
121671
|
-
if (marker &&
|
|
121672
|
-
reasons.set(marker,
|
|
121673
|
-
await writeLine2(ctx, `${v.sha} ${v.timestamp} ${message}${suffix}${marker ? ` ${marker}` : ""}`);
|
|
122499
|
+
const target2 = v.rollbackTarget;
|
|
122500
|
+
const marker = target2 && target2.mode !== "in-window" ? target2.mode === "rebuild" ? "[rebuild required]" : "[not a rollback target]" : null;
|
|
122501
|
+
if (marker && target2)
|
|
122502
|
+
reasons.set(marker, target2.explanation);
|
|
122503
|
+
await writeLine2(ctx, `${v.sha} ${v.timestamp} ${message}${noteLabel ? ` · ${noteLabel}` : ""}${suffix}${marker ? ` ${marker}` : ""}`);
|
|
121674
122504
|
}
|
|
121675
122505
|
for (const [marker, explanation] of reasons) {
|
|
121676
122506
|
await writeLine2(ctx, `
|
|
@@ -121684,8 +122514,8 @@ ${marker} ${explanation}`);
|
|
|
121684
122514
|
head,
|
|
121685
122515
|
patch: options.patch
|
|
121686
122516
|
});
|
|
121687
|
-
const { summary, files } = result;
|
|
121688
|
-
await writeLine2(ctx, `${
|
|
122517
|
+
const { summary: summary2, files } = result;
|
|
122518
|
+
await writeLine2(ctx, `${summary2.filesChanged} file${summary2.filesChanged === 1 ? "" : "s"} changed · ${import_picocolors8.default.green(`+${summary2.additions}`)} ${import_picocolors8.default.red(`−${summary2.deletions}`)} (${result.base.slice(0, 10)} → ${result.head.slice(0, 10)})`);
|
|
121689
122519
|
for (const f of files) {
|
|
121690
122520
|
const stat3 = f.binary ? import_picocolors8.default.dim("binary") : `${import_picocolors8.default.green(`+${f.additions}`)} ${import_picocolors8.default.red(`−${f.deletions}`)}`;
|
|
121691
122521
|
await writeLine2(ctx, ` ${f.status} ${f.path} ${stat3}${f.truncated ? import_picocolors8.default.dim(" (truncated)") : ""}`);
|
|
@@ -122376,8 +123206,209 @@ async function renderHumanStatus(ctx, result) {
|
|
|
122376
123206
|
}
|
|
122377
123207
|
}
|
|
122378
123208
|
|
|
122379
|
-
// src/commands/
|
|
123209
|
+
// src/commands/telemetry.ts
|
|
123210
|
+
init_dist();
|
|
122380
123211
|
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
123212
|
+
|
|
123213
|
+
// src/telemetry.ts
|
|
123214
|
+
init_dist();
|
|
123215
|
+
import { createInterface } from "node:readline";
|
|
123216
|
+
// package.json
|
|
123217
|
+
var package_default2 = {
|
|
123218
|
+
name: "percher",
|
|
123219
|
+
version: "1.3.0",
|
|
123220
|
+
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
123221
|
+
type: "module",
|
|
123222
|
+
bin: {
|
|
123223
|
+
percher: "./dist/bin/percher.js"
|
|
123224
|
+
},
|
|
123225
|
+
main: "./dist/src/index.js",
|
|
123226
|
+
types: "./dist/src/index.d.ts",
|
|
123227
|
+
exports: {
|
|
123228
|
+
".": {
|
|
123229
|
+
types: "./dist/src/index.d.ts",
|
|
123230
|
+
import: "./dist/src/index.js",
|
|
123231
|
+
default: "./dist/src/index.js"
|
|
123232
|
+
}
|
|
123233
|
+
},
|
|
123234
|
+
files: [
|
|
123235
|
+
"dist",
|
|
123236
|
+
"THIRD-PARTY-NOTICES.txt"
|
|
123237
|
+
],
|
|
123238
|
+
publishConfig: {
|
|
123239
|
+
access: "public"
|
|
123240
|
+
},
|
|
123241
|
+
scripts: {
|
|
123242
|
+
build: `tsc -p tsconfig.json && tsc-alias -p tsconfig.json && bun build bin/percher.ts --outfile dist/bin/percher.js --target node --format esm --metafile=bundle-meta.json && node ../../scripts/bundle-notices.mjs . bundle-meta.json && node scripts/copy-templates.mjs && node -e "require('fs').chmodSync('dist/bin/percher.js',0o755)"`,
|
|
123243
|
+
test: "bun test",
|
|
123244
|
+
typecheck: "tsc --noEmit"
|
|
123245
|
+
},
|
|
123246
|
+
dependencies: {
|
|
123247
|
+
"@percher/client": "^1.3.0",
|
|
123248
|
+
"@percher/core": "^1.3.0",
|
|
123249
|
+
"@percher/toml": "^1.0.4",
|
|
123250
|
+
cac: "^7.0.0",
|
|
123251
|
+
picocolors: "^1.1.1"
|
|
123252
|
+
},
|
|
123253
|
+
devDependencies: {
|
|
123254
|
+
"bun-types": "^1.1.0",
|
|
123255
|
+
"tsc-alias": "^1.8.17"
|
|
123256
|
+
},
|
|
123257
|
+
engines: {
|
|
123258
|
+
bun: ">=1.0.0",
|
|
123259
|
+
node: ">=22.0.0"
|
|
123260
|
+
},
|
|
123261
|
+
license: "FSL-1.1-MIT",
|
|
123262
|
+
author: "Mattias Malmborg",
|
|
123263
|
+
repository: {
|
|
123264
|
+
type: "git",
|
|
123265
|
+
url: "https://github.com/mattiasmalmborg/percher"
|
|
123266
|
+
},
|
|
123267
|
+
keywords: [
|
|
123268
|
+
"hosting",
|
|
123269
|
+
"deploy",
|
|
123270
|
+
"cli",
|
|
123271
|
+
"paas",
|
|
123272
|
+
"bun",
|
|
123273
|
+
"ai"
|
|
123274
|
+
]
|
|
123275
|
+
};
|
|
123276
|
+
|
|
123277
|
+
// src/telemetry.ts
|
|
123278
|
+
var VERSION = package_default2.version;
|
|
123279
|
+
function trackEvent(command, result, errorType) {
|
|
123280
|
+
if (!telemetryState().enabled)
|
|
123281
|
+
return;
|
|
123282
|
+
const body = JSON.stringify({
|
|
123283
|
+
cliVersion: VERSION,
|
|
123284
|
+
command,
|
|
123285
|
+
result,
|
|
123286
|
+
errorType,
|
|
123287
|
+
os: `${process.platform}-${process.arch}`,
|
|
123288
|
+
bunVersion: typeof Bun !== "undefined" ? Bun.version : undefined
|
|
123289
|
+
});
|
|
123290
|
+
fetch(`${resolveApiUrl()}/telemetry/cli`, {
|
|
123291
|
+
method: "POST",
|
|
123292
|
+
headers: { "Content-Type": "application/json" },
|
|
123293
|
+
body,
|
|
123294
|
+
signal: AbortSignal.timeout(3000)
|
|
123295
|
+
}).catch(() => {});
|
|
123296
|
+
}
|
|
123297
|
+
function lineAsker(input, output, onInterrupt = () => process.exit(130)) {
|
|
123298
|
+
return (question, signal) => new Promise((resolve11) => {
|
|
123299
|
+
const rl = createInterface({
|
|
123300
|
+
input,
|
|
123301
|
+
output,
|
|
123302
|
+
terminal: input.isTTY === true
|
|
123303
|
+
});
|
|
123304
|
+
let settled = false;
|
|
123305
|
+
const finish = (answer) => {
|
|
123306
|
+
if (settled)
|
|
123307
|
+
return;
|
|
123308
|
+
settled = true;
|
|
123309
|
+
signal.removeEventListener("abort", onAbort);
|
|
123310
|
+
if (answer === null)
|
|
123311
|
+
output.write(`
|
|
123312
|
+
`);
|
|
123313
|
+
resolve11(answer);
|
|
123314
|
+
rl.close();
|
|
123315
|
+
};
|
|
123316
|
+
const onAbort = () => finish(null);
|
|
123317
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
123318
|
+
rl.on("line", (line) => finish(line));
|
|
123319
|
+
rl.on("close", () => finish(null));
|
|
123320
|
+
rl.on("SIGINT", () => {
|
|
123321
|
+
finish(null);
|
|
123322
|
+
onInterrupt();
|
|
123323
|
+
});
|
|
123324
|
+
rl.setPrompt(question);
|
|
123325
|
+
rl.prompt();
|
|
123326
|
+
if (signal.aborted)
|
|
123327
|
+
finish(null);
|
|
123328
|
+
});
|
|
123329
|
+
}
|
|
123330
|
+
var askOnStdin = lineAsker(process.stdin, process.stderr);
|
|
123331
|
+
var ANSWER_TIMEOUT_MS = 20000;
|
|
123332
|
+
var CI_VARS = ["CONTINUOUS_INTEGRATION", "BUILD_NUMBER", "TF_BUILD", "JENKINS_URL"];
|
|
123333
|
+
var AGENT_VARS = [
|
|
123334
|
+
"CLAUDECODE",
|
|
123335
|
+
"CURSOR_AGENT",
|
|
123336
|
+
"CURSOR_TRACE_ID",
|
|
123337
|
+
"CODEX_SANDBOX",
|
|
123338
|
+
"CODEX_CI",
|
|
123339
|
+
"GITHUB_ACTIONS"
|
|
123340
|
+
];
|
|
123341
|
+
function isUnattended(env) {
|
|
123342
|
+
const ci = env.CI;
|
|
123343
|
+
if (ci !== undefined && ci !== "" && ci !== "0" && ci !== "false")
|
|
123344
|
+
return true;
|
|
123345
|
+
return [...CI_VARS, ...AGENT_VARS].some((key) => Boolean(env[key]));
|
|
123346
|
+
}
|
|
123347
|
+
var realTimer = (fire, ms) => {
|
|
123348
|
+
const handle = setTimeout(fire, ms);
|
|
123349
|
+
return () => clearTimeout(handle);
|
|
123350
|
+
};
|
|
123351
|
+
async function askTelemetryConsentOnce(ctx, argv, command, question) {
|
|
123352
|
+
if (command === "telemetry" || argv.includes("--json"))
|
|
123353
|
+
return;
|
|
123354
|
+
if (ctx.stdinIsInteractive !== true || !question.stderrIsTTY)
|
|
123355
|
+
return;
|
|
123356
|
+
if (isUnattended(ctx.env))
|
|
123357
|
+
return;
|
|
123358
|
+
const state = telemetryState();
|
|
123359
|
+
if (state.envOptOut || state.stored)
|
|
123360
|
+
return;
|
|
123361
|
+
const timeout = new AbortController;
|
|
123362
|
+
const cancel = (question.setTimer ?? realTimer)(() => timeout.abort(), ANSWER_TIMEOUT_MS);
|
|
123363
|
+
let answer;
|
|
123364
|
+
try {
|
|
123365
|
+
answer = await question.ask("Send anonymous usage statistics to Percher? (y/N) ", timeout.signal);
|
|
123366
|
+
} finally {
|
|
123367
|
+
cancel();
|
|
123368
|
+
}
|
|
123369
|
+
if (answer === null)
|
|
123370
|
+
return;
|
|
123371
|
+
const enabled = /^y(es)?$/i.test(answer.trim());
|
|
123372
|
+
try {
|
|
123373
|
+
saveTelemetryAnswer(enabled, VERSION);
|
|
123374
|
+
} catch {
|
|
123375
|
+
await writeErrLine(ctx, "Could not save the answer; you will be asked again.");
|
|
123376
|
+
return;
|
|
123377
|
+
}
|
|
123378
|
+
await writeErrLine(ctx, enabled ? "Usage statistics on. Turn off: percher telemetry off" : "Usage statistics off. Turn on: percher telemetry on");
|
|
123379
|
+
}
|
|
123380
|
+
function telemetryStatusLine(state = telemetryState()) {
|
|
123381
|
+
const stored = state.stored ? `stored answer: ${state.stored.enabled ? "on" : "off"}` : null;
|
|
123382
|
+
if (state.envOptOut) {
|
|
123383
|
+
return `Telemetry: off (env opt-out: ${state.envOptOut}${stored ? `; ${stored}` : ""})`;
|
|
123384
|
+
}
|
|
123385
|
+
if (state.stored)
|
|
123386
|
+
return `Telemetry: ${state.stored.enabled ? "on" : "off"} (stored answer)`;
|
|
123387
|
+
return "Telemetry: off (undecided)";
|
|
123388
|
+
}
|
|
123389
|
+
|
|
123390
|
+
// src/commands/telemetry.ts
|
|
123391
|
+
function registerTelemetryCommands(cli, ctx) {
|
|
123392
|
+
cli.command("telemetry [action]", "Anonymous usage statistics: on | off | status").action(async (action) => {
|
|
123393
|
+
if (action === "on" || action === "off") {
|
|
123394
|
+
try {
|
|
123395
|
+
saveTelemetryAnswer(action === "on", VERSION);
|
|
123396
|
+
} catch {
|
|
123397
|
+
await writeErrLine(ctx, `${import_picocolors16.default.red("✗")} Could not save the answer.`);
|
|
123398
|
+
throw new SilentExitError;
|
|
123399
|
+
}
|
|
123400
|
+
} else if (action !== undefined && action !== "status") {
|
|
123401
|
+
await writeErrLine(ctx, `${import_picocolors16.default.red("✗")} Usage: percher telemetry on|off|status`);
|
|
123402
|
+
throw new SilentExitError;
|
|
123403
|
+
}
|
|
123404
|
+
const state = telemetryState();
|
|
123405
|
+
const overridden = action === "on" && state.envOptOut !== null;
|
|
123406
|
+
await writeLine2(ctx, `${telemetryStatusLine(state)}${overridden ? "; the environment variable still wins." : ""}`);
|
|
123407
|
+
});
|
|
123408
|
+
}
|
|
123409
|
+
|
|
123410
|
+
// src/commands/token.ts
|
|
123411
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
122381
123412
|
var VALID_SCOPES = ["deploy", "env", "read", "full"];
|
|
122382
123413
|
function scopeLabel(scopes, appName) {
|
|
122383
123414
|
const s = scopes && scopes.length > 0 ? scopes.join("+") : "full";
|
|
@@ -122386,22 +123417,22 @@ function scopeLabel(scopes, appName) {
|
|
|
122386
123417
|
function registerTokenCommands(cli, ctx) {
|
|
122387
123418
|
cli.command("token [action] [arg]", "Manage API tokens: create | list | revoke").option("--scope <scope>", "(create) deploy | env | read | full (default: full, account-wide unless --app)").option("--app <name>", "(create) bind the token to a single app").option("--ttl-days <n>", "(create) token lifetime in days (default 90, max 365)").action(async (action, arg, options) => {
|
|
122388
123419
|
if (!ctx.client.token) {
|
|
122389
|
-
await writeLine2(ctx, `${
|
|
123420
|
+
await writeLine2(ctx, `${import_picocolors17.default.red("✗")} Not logged in. Run: percher login`);
|
|
122390
123421
|
throw new SilentExitError;
|
|
122391
123422
|
}
|
|
122392
123423
|
if (action === "create") {
|
|
122393
123424
|
if (!arg) {
|
|
122394
|
-
await writeLine2(ctx, `${
|
|
123425
|
+
await writeLine2(ctx, `${import_picocolors17.default.red("✗")} A name is required. Usage: percher token create <name> [--scope deploy] [--app <name>]`);
|
|
122395
123426
|
throw new SilentExitError;
|
|
122396
123427
|
}
|
|
122397
123428
|
const scope = options.scope ?? "full";
|
|
122398
123429
|
if (!VALID_SCOPES.includes(scope)) {
|
|
122399
|
-
await writeLine2(ctx, `${
|
|
123430
|
+
await writeLine2(ctx, `${import_picocolors17.default.red("✗")} Invalid --scope "${options.scope}". Use one of: ${VALID_SCOPES.join(", ")}.`);
|
|
122400
123431
|
throw new SilentExitError;
|
|
122401
123432
|
}
|
|
122402
123433
|
const ttlDays = options.ttlDays !== undefined ? Number(options.ttlDays) : undefined;
|
|
122403
123434
|
if (ttlDays !== undefined && (!Number.isInteger(ttlDays) || ttlDays <= 0)) {
|
|
122404
|
-
await writeLine2(ctx, `${
|
|
123435
|
+
await writeLine2(ctx, `${import_picocolors17.default.red("✗")} --ttl-days must be a positive whole number.`);
|
|
122405
123436
|
throw new SilentExitError;
|
|
122406
123437
|
}
|
|
122407
123438
|
const created = await tokenCreate(ctx, {
|
|
@@ -122410,36 +123441,36 @@ function registerTokenCommands(cli, ctx) {
|
|
|
122410
123441
|
app: options.app,
|
|
122411
123442
|
ttlDays
|
|
122412
123443
|
});
|
|
122413
|
-
await writeLine2(ctx, `${
|
|
123444
|
+
await writeLine2(ctx, `${import_picocolors17.default.green("✓")} Token created: ${import_picocolors17.default.bold(created.name)} ${import_picocolors17.default.dim(`(${scopeLabel(created.scopes, created.appName)})`)}`);
|
|
122414
123445
|
await writeLine2(ctx, "");
|
|
122415
|
-
await writeLine2(ctx, ` ${
|
|
122416
|
-
await writeLine2(ctx,
|
|
123446
|
+
await writeLine2(ctx, ` ${import_picocolors17.default.bold(created.token)}`);
|
|
123447
|
+
await writeLine2(ctx, import_picocolors17.default.yellow(" ↑ Store this now — the secret is shown only once and can't be retrieved."));
|
|
122417
123448
|
await writeLine2(ctx, "");
|
|
122418
|
-
await writeLine2(ctx,
|
|
122419
|
-
await writeLine2(ctx,
|
|
123449
|
+
await writeLine2(ctx, import_picocolors17.default.dim(" Use it in CI / an agent:"));
|
|
123450
|
+
await writeLine2(ctx, import_picocolors17.default.dim(` PERCHER_TOKEN=${created.token} bunx percher publish`));
|
|
122420
123451
|
return;
|
|
122421
123452
|
}
|
|
122422
123453
|
if (action === "list") {
|
|
122423
123454
|
const tokens = await tokenList(ctx);
|
|
122424
123455
|
if (tokens.length === 0) {
|
|
122425
|
-
await writeLine2(ctx,
|
|
123456
|
+
await writeLine2(ctx, import_picocolors17.default.dim("No API tokens."));
|
|
122426
123457
|
return;
|
|
122427
123458
|
}
|
|
122428
123459
|
for (const t of tokens) {
|
|
122429
123460
|
const expires = t.expiresAt ? `expires ${new Date(t.expiresAt).toISOString().slice(0, 10)}` : "no expiry";
|
|
122430
|
-
await writeLine2(ctx, `${
|
|
123461
|
+
await writeLine2(ctx, `${import_picocolors17.default.bold(t.id)} ${t.name.padEnd(20)} ${import_picocolors17.default.dim(scopeLabel(t.scopes, t.appName))} ${import_picocolors17.default.dim(expires)}`);
|
|
122431
123462
|
}
|
|
122432
123463
|
await writeLine2(ctx, "");
|
|
122433
|
-
await writeLine2(ctx,
|
|
123464
|
+
await writeLine2(ctx, import_picocolors17.default.dim("Revoke one with: percher token revoke <id>"));
|
|
122434
123465
|
return;
|
|
122435
123466
|
}
|
|
122436
123467
|
if (action === "revoke") {
|
|
122437
123468
|
if (!arg) {
|
|
122438
|
-
await writeLine2(ctx, `${
|
|
123469
|
+
await writeLine2(ctx, `${import_picocolors17.default.red("✗")} A token id is required. Usage: percher token revoke <id> (list ids with \`percher token list\`).`);
|
|
122439
123470
|
throw new SilentExitError;
|
|
122440
123471
|
}
|
|
122441
123472
|
await tokenRevoke(ctx, { id: arg });
|
|
122442
|
-
await writeLine2(ctx, `${
|
|
123473
|
+
await writeLine2(ctx, `${import_picocolors17.default.green("✓")} Token revoked.`);
|
|
122443
123474
|
return;
|
|
122444
123475
|
}
|
|
122445
123476
|
throw new Error(`Unknown token action "${action ?? ""}". Use: create | list | revoke.`);
|
|
@@ -122450,17 +123481,17 @@ function registerTokenCommands(cli, ctx) {
|
|
|
122450
123481
|
}
|
|
122451
123482
|
|
|
122452
123483
|
// src/commands/transfers.ts
|
|
122453
|
-
var
|
|
123484
|
+
var import_picocolors18 = __toESM(require_picocolors(), 1);
|
|
122454
123485
|
function registerTransfersCommands(cli, ctx) {
|
|
122455
123486
|
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) => {
|
|
122456
123487
|
if (options.list) {
|
|
122457
123488
|
const rows = await transferListForApp(ctx, { app: options.app });
|
|
122458
123489
|
if (rows.length === 0) {
|
|
122459
|
-
await writeLine2(ctx,
|
|
123490
|
+
await writeLine2(ctx, import_picocolors18.default.dim("No transfers for this app."));
|
|
122460
123491
|
return;
|
|
122461
123492
|
}
|
|
122462
123493
|
for (const r of rows) {
|
|
122463
|
-
const status2 = r.status === "pending" ?
|
|
123494
|
+
const status2 = r.status === "pending" ? import_picocolors18.default.yellow("pending") : r.status === "accepted" ? import_picocolors18.default.green("accepted") : import_picocolors18.default.dim(r.status);
|
|
122464
123495
|
await writeLine2(ctx, `${r.id} ${status2.padEnd(20)} → ${r.toEmail} (${r.createdAt})`);
|
|
122465
123496
|
}
|
|
122466
123497
|
return;
|
|
@@ -122473,7 +123504,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
122473
123504
|
app: options.app,
|
|
122474
123505
|
transferId: emailOrTransferId
|
|
122475
123506
|
});
|
|
122476
|
-
await writeLine2(ctx, `${
|
|
123507
|
+
await writeLine2(ctx, `${import_picocolors18.default.green("✓")} Cancelled transfer ${emailOrTransferId}`);
|
|
122477
123508
|
return;
|
|
122478
123509
|
}
|
|
122479
123510
|
if (!emailOrTransferId) {
|
|
@@ -122483,17 +123514,17 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
122483
123514
|
app: options.app,
|
|
122484
123515
|
email: emailOrTransferId
|
|
122485
123516
|
});
|
|
122486
|
-
await writeLine2(ctx, `${
|
|
122487
|
-
await writeLine2(ctx,
|
|
123517
|
+
await writeLine2(ctx, `${import_picocolors18.default.green("✓")} Transfer initiated to ${initiated.toEmail} (id ${initiated.id})`);
|
|
123518
|
+
await writeLine2(ctx, import_picocolors18.default.dim(`Expires ${new Date(initiated.expiresAt).toLocaleDateString()}. The recipient must accept via 'percher transfers accept ${initiated.id}'.`));
|
|
122488
123519
|
if (initiated.notes) {
|
|
122489
|
-
await writeLine2(ctx,
|
|
123520
|
+
await writeLine2(ctx, import_picocolors18.default.yellow(` ⚠ ${initiated.notes}`));
|
|
122490
123521
|
}
|
|
122491
123522
|
});
|
|
122492
123523
|
cli.command("transfers [action] [transferId]", "Incoming ownership transfers: list (default) | accept <transferId> | decline <transferId>").action(async (action, transferId) => {
|
|
122493
123524
|
if (action === undefined || action === "list") {
|
|
122494
123525
|
const rows = await transfersIncoming(ctx, {});
|
|
122495
123526
|
if (rows.length === 0) {
|
|
122496
|
-
await writeLine2(ctx,
|
|
123527
|
+
await writeLine2(ctx, import_picocolors18.default.dim("No pending incoming transfers."));
|
|
122497
123528
|
return;
|
|
122498
123529
|
}
|
|
122499
123530
|
for (const r of rows) {
|
|
@@ -122506,7 +123537,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
122506
123537
|
throw new Error("Usage: percher transfers accept <transferId>");
|
|
122507
123538
|
}
|
|
122508
123539
|
const accepted = await transfersAccept(ctx, { transferId });
|
|
122509
|
-
await writeLine2(ctx, `${
|
|
123540
|
+
await writeLine2(ctx, `${import_picocolors18.default.green("✓")} You now own ${import_picocolors18.default.cyan(accepted.appName)}. Run 'percher open ${accepted.appName}' to see it.`);
|
|
122510
123541
|
return;
|
|
122511
123542
|
}
|
|
122512
123543
|
if (action === "decline") {
|
|
@@ -122514,7 +123545,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
122514
123545
|
throw new Error("Usage: percher transfers decline <transferId>");
|
|
122515
123546
|
}
|
|
122516
123547
|
await transfersDecline(ctx, { transferId });
|
|
122517
|
-
await writeLine2(ctx, `${
|
|
123548
|
+
await writeLine2(ctx, `${import_picocolors18.default.green("✓")} Declined transfer ${transferId}.`);
|
|
122518
123549
|
return;
|
|
122519
123550
|
}
|
|
122520
123551
|
throw new Error(`Unknown transfers action "${action}". Use list | accept <id> | decline <id>.`);
|
|
@@ -122543,9 +123574,9 @@ async function openUrl(url2) {
|
|
|
122543
123574
|
|
|
122544
123575
|
// src/prompt.ts
|
|
122545
123576
|
import { stdin as input, stdout as output } from "node:process";
|
|
122546
|
-
import { createInterface } from "node:readline/promises";
|
|
123577
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
122547
123578
|
async function prompt(question, options) {
|
|
122548
|
-
const rl =
|
|
123579
|
+
const rl = createInterface2({ input, output });
|
|
122549
123580
|
try {
|
|
122550
123581
|
const suffix = options?.default ? ` [${options.default}]` : "";
|
|
122551
123582
|
const answer = await rl.question(`${question}${suffix} `);
|
|
@@ -122555,111 +123586,6 @@ async function prompt(question, options) {
|
|
|
122555
123586
|
}
|
|
122556
123587
|
}
|
|
122557
123588
|
|
|
122558
|
-
// src/telemetry.ts
|
|
122559
|
-
init_dist();
|
|
122560
|
-
// package.json
|
|
122561
|
-
var package_default2 = {
|
|
122562
|
-
name: "percher",
|
|
122563
|
-
version: "1.1.0",
|
|
122564
|
-
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
122565
|
-
type: "module",
|
|
122566
|
-
bin: {
|
|
122567
|
-
percher: "./dist/bin/percher.js"
|
|
122568
|
-
},
|
|
122569
|
-
main: "./dist/src/index.js",
|
|
122570
|
-
types: "./dist/src/index.d.ts",
|
|
122571
|
-
exports: {
|
|
122572
|
-
".": {
|
|
122573
|
-
types: "./dist/src/index.d.ts",
|
|
122574
|
-
import: "./dist/src/index.js",
|
|
122575
|
-
default: "./dist/src/index.js"
|
|
122576
|
-
}
|
|
122577
|
-
},
|
|
122578
|
-
files: [
|
|
122579
|
-
"dist",
|
|
122580
|
-
"THIRD-PARTY-NOTICES.txt"
|
|
122581
|
-
],
|
|
122582
|
-
publishConfig: {
|
|
122583
|
-
access: "public"
|
|
122584
|
-
},
|
|
122585
|
-
scripts: {
|
|
122586
|
-
build: `tsc -p tsconfig.json && tsc-alias -p tsconfig.json && bun build bin/percher.ts --outfile dist/bin/percher.js --target node --format esm --metafile=bundle-meta.json && node ../../scripts/bundle-notices.mjs . bundle-meta.json && node scripts/copy-templates.mjs && node -e "require('fs').chmodSync('dist/bin/percher.js',0o755)"`,
|
|
122587
|
-
test: "bun test",
|
|
122588
|
-
typecheck: "tsc --noEmit"
|
|
122589
|
-
},
|
|
122590
|
-
dependencies: {
|
|
122591
|
-
"@percher/client": "^1.1.0",
|
|
122592
|
-
"@percher/core": "^1.1.0",
|
|
122593
|
-
"@percher/toml": "^1.0.3",
|
|
122594
|
-
cac: "^7.0.0",
|
|
122595
|
-
picocolors: "^1.1.1"
|
|
122596
|
-
},
|
|
122597
|
-
devDependencies: {
|
|
122598
|
-
"bun-types": "^1.1.0",
|
|
122599
|
-
"tsc-alias": "^1.8.17"
|
|
122600
|
-
},
|
|
122601
|
-
engines: {
|
|
122602
|
-
bun: ">=1.0.0",
|
|
122603
|
-
node: ">=22.0.0"
|
|
122604
|
-
},
|
|
122605
|
-
license: "FSL-1.1-MIT",
|
|
122606
|
-
author: "Mattias Malmborg",
|
|
122607
|
-
repository: {
|
|
122608
|
-
type: "git",
|
|
122609
|
-
url: "https://github.com/mattiasmalmborg/percher"
|
|
122610
|
-
},
|
|
122611
|
-
keywords: [
|
|
122612
|
-
"hosting",
|
|
122613
|
-
"deploy",
|
|
122614
|
-
"cli",
|
|
122615
|
-
"paas",
|
|
122616
|
-
"bun",
|
|
122617
|
-
"ai"
|
|
122618
|
-
]
|
|
122619
|
-
};
|
|
122620
|
-
|
|
122621
|
-
// src/telemetry.ts
|
|
122622
|
-
var VERSION = package_default2.version;
|
|
122623
|
-
function isDisabled() {
|
|
122624
|
-
return process.env.PERCHER_NO_TELEMETRY === "1" || process.env.PERCHER_NO_TELEMETRY === "true" || process.env.DO_NOT_TRACK === "1";
|
|
122625
|
-
}
|
|
122626
|
-
function trackEvent(command, result, errorType) {
|
|
122627
|
-
if (isDisabled())
|
|
122628
|
-
return;
|
|
122629
|
-
const body = JSON.stringify({
|
|
122630
|
-
cliVersion: VERSION,
|
|
122631
|
-
command,
|
|
122632
|
-
result,
|
|
122633
|
-
errorType,
|
|
122634
|
-
os: `${process.platform}-${process.arch}`,
|
|
122635
|
-
bunVersion: typeof Bun !== "undefined" ? Bun.version : undefined
|
|
122636
|
-
});
|
|
122637
|
-
fetch(`${resolveApiUrl()}/telemetry/cli`, {
|
|
122638
|
-
method: "POST",
|
|
122639
|
-
headers: { "Content-Type": "application/json" },
|
|
122640
|
-
body,
|
|
122641
|
-
signal: AbortSignal.timeout(3000)
|
|
122642
|
-
}).catch(() => {});
|
|
122643
|
-
}
|
|
122644
|
-
async function showTelemetryNotice() {
|
|
122645
|
-
if (isDisabled())
|
|
122646
|
-
return;
|
|
122647
|
-
const { homedir: homedir2 } = await import("node:os");
|
|
122648
|
-
const { existsSync: existsSync18, mkdirSync: mkdirSync7, writeFileSync: writeFileSync11 } = await import("node:fs");
|
|
122649
|
-
const { join: join28 } = await import("node:path");
|
|
122650
|
-
const configDir = join28(homedir2(), ".percher");
|
|
122651
|
-
const markerFile = join28(configDir, ".telemetry-notice-shown");
|
|
122652
|
-
if (existsSync18(markerFile))
|
|
122653
|
-
return;
|
|
122654
|
-
console.error("Percher sends non-account-linked usage stats (CLI version, command, result, error type, OS, Bun version).");
|
|
122655
|
-
console.error(`Disable with PERCHER_NO_TELEMETRY=1 or DO_NOT_TRACK=1
|
|
122656
|
-
`);
|
|
122657
|
-
try {
|
|
122658
|
-
mkdirSync7(configDir, { recursive: true });
|
|
122659
|
-
writeFileSync11(markerFile, new Date().toISOString());
|
|
122660
|
-
} catch {}
|
|
122661
|
-
}
|
|
122662
|
-
|
|
122663
123589
|
// src/context.ts
|
|
122664
123590
|
async function createCliContext() {
|
|
122665
123591
|
const client = new PercherClient({ clientVersion: `percher-cli/${VERSION}` });
|
|
@@ -122693,52 +123619,52 @@ async function createCliContext() {
|
|
|
122693
123619
|
|
|
122694
123620
|
// src/output.ts
|
|
122695
123621
|
init_dist();
|
|
122696
|
-
var
|
|
123622
|
+
var import_picocolors19 = __toESM(require_picocolors(), 1);
|
|
122697
123623
|
async function renderError(stderr, error48) {
|
|
122698
123624
|
const writer = stderr.getWriter();
|
|
122699
123625
|
const encoder = new TextEncoder;
|
|
122700
123626
|
const lines = [];
|
|
122701
123627
|
if (error48 instanceof PercherTomlError) {
|
|
122702
|
-
lines.push(`${
|
|
123628
|
+
lines.push(`${import_picocolors19.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
122703
123629
|
if (error48.tomlLine !== undefined) {
|
|
122704
|
-
lines.push(
|
|
123630
|
+
lines.push(import_picocolors19.default.dim(` at percher.toml line ${error48.tomlLine}`));
|
|
122705
123631
|
}
|
|
122706
123632
|
for (const issue2 of error48.issues ?? []) {
|
|
122707
|
-
lines.push(`${
|
|
123633
|
+
lines.push(`${import_picocolors19.default.dim(" · ") + import_picocolors19.default.yellow(issue2.path.join("."))}: ${issue2.message}`);
|
|
122708
123634
|
}
|
|
122709
123635
|
} else if (error48 instanceof SunsetError) {
|
|
122710
123636
|
if (error48.gateCode === "platform_delete_gated") {
|
|
122711
|
-
lines.push(`${
|
|
123637
|
+
lines.push(`${import_picocolors19.default.yellow("Percher is shutting down — deletes are paused.")}`);
|
|
122712
123638
|
lines.push(error48.message);
|
|
122713
|
-
lines.push(
|
|
122714
|
-
lines.push(
|
|
123639
|
+
lines.push(import_picocolors19.default.dim(` To delete and permanently forfeit your export window, confirm with your password in the dashboard: ${error48.dashboardUrl}`));
|
|
123640
|
+
lines.push(import_picocolors19.default.dim(" The CLI cannot perform this delete during sunset — it must go through the dashboard."));
|
|
122715
123641
|
} else {
|
|
122716
|
-
lines.push(`${
|
|
123642
|
+
lines.push(`${import_picocolors19.default.yellow("Percher is in read-only mode ahead of shutdown.")}`);
|
|
122717
123643
|
lines.push(error48.message);
|
|
122718
|
-
lines.push(
|
|
123644
|
+
lines.push(import_picocolors19.default.dim(` Your apps keep running. Export them any time from the dashboard: ${error48.dashboardUrl}`));
|
|
122719
123645
|
}
|
|
122720
|
-
lines.push(
|
|
123646
|
+
lines.push(import_picocolors19.default.dim(` Final data deletion: ${error48.finalDeletionDate}`));
|
|
122721
123647
|
} else if (error48 instanceof PercherApiError) {
|
|
122722
123648
|
if (error48.status === 502 || error48.status === 503) {
|
|
122723
|
-
lines.push(`${
|
|
123649
|
+
lines.push(`${import_picocolors19.default.red("error:")} Percher API is temporarily unavailable (HTTP ${error48.status}). Try again in a few seconds.`);
|
|
122724
123650
|
} else {
|
|
122725
|
-
lines.push(`${
|
|
122726
|
-
lines.push(
|
|
123651
|
+
lines.push(`${import_picocolors19.default.red("error:")} ${error48.message}`);
|
|
123652
|
+
lines.push(import_picocolors19.default.dim(` ${error48.code} (HTTP ${error48.status})`));
|
|
122727
123653
|
}
|
|
122728
123654
|
if (error48.requestId)
|
|
122729
|
-
lines.push(
|
|
123655
|
+
lines.push(import_picocolors19.default.dim(` request: ${error48.requestId}`));
|
|
122730
123656
|
} else if (error48 instanceof PercherCoreError) {
|
|
122731
|
-
lines.push(`${
|
|
123657
|
+
lines.push(`${import_picocolors19.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
122732
123658
|
if (error48.hint)
|
|
122733
|
-
lines.push(
|
|
123659
|
+
lines.push(import_picocolors19.default.dim(` ${error48.hint}`));
|
|
122734
123660
|
} else if (error48 instanceof Error) {
|
|
122735
|
-
lines.push(`${
|
|
123661
|
+
lines.push(`${import_picocolors19.default.red("unexpected error:")} ${error48.message}`);
|
|
122736
123662
|
if (error48.stack)
|
|
122737
|
-
lines.push(
|
|
123663
|
+
lines.push(import_picocolors19.default.dim(error48.stack.split(`
|
|
122738
123664
|
`).slice(1, 4).join(`
|
|
122739
123665
|
`)));
|
|
122740
123666
|
} else {
|
|
122741
|
-
lines.push(`${
|
|
123667
|
+
lines.push(`${import_picocolors19.default.red("unexpected error:")} ${String(error48)}`);
|
|
122742
123668
|
}
|
|
122743
123669
|
try {
|
|
122744
123670
|
await writer.write(encoder.encode(`${lines.join(`
|
|
@@ -122750,7 +123676,7 @@ async function renderError(stderr, error48) {
|
|
|
122750
123676
|
}
|
|
122751
123677
|
|
|
122752
123678
|
// src/version-check.ts
|
|
122753
|
-
var
|
|
123679
|
+
var import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
122754
123680
|
function isNewerStableVersion(latest, current) {
|
|
122755
123681
|
const stable = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
122756
123682
|
if (typeof latest !== "string" || latest.length > 64 || current.length > 64 || !stable.test(latest) || !stable.test(current))
|
|
@@ -122777,16 +123703,16 @@ async function checkForUpdates() {
|
|
|
122777
123703
|
const data2 = await res.json();
|
|
122778
123704
|
const latest = data2.version;
|
|
122779
123705
|
if (isNewerStableVersion(latest, VERSION)) {
|
|
122780
|
-
console.error(
|
|
123706
|
+
console.error(import_picocolors20.default.yellow(`
|
|
122781
123707
|
Update available: ${VERSION} → ${latest}`));
|
|
122782
|
-
console.error(
|
|
123708
|
+
console.error(import_picocolors20.default.dim(`Run: bunx percher@latest
|
|
122783
123709
|
`));
|
|
122784
123710
|
}
|
|
122785
123711
|
} catch {}
|
|
122786
123712
|
}
|
|
122787
123713
|
|
|
122788
123714
|
// src/index.ts
|
|
122789
|
-
async function run(argv, ctxOverride) {
|
|
123715
|
+
async function run(argv, ctxOverride, options = {}) {
|
|
122790
123716
|
const cli = cac("percher");
|
|
122791
123717
|
const ctx = ctxOverride ?? await createCliContext();
|
|
122792
123718
|
registerAppsCommands(cli, ctx);
|
|
@@ -122802,6 +123728,7 @@ async function run(argv, ctxOverride) {
|
|
|
122802
123728
|
registerMigrateCommands(cli, ctx);
|
|
122803
123729
|
registerSharingCommands(cli, ctx);
|
|
122804
123730
|
registerStatusCommands(cli, ctx);
|
|
123731
|
+
registerTelemetryCommands(cli, ctx);
|
|
122805
123732
|
registerTokenCommands(cli, ctx);
|
|
122806
123733
|
registerTransfersCommands(cli, ctx);
|
|
122807
123734
|
registerAdminCommands(cli, ctx);
|
|
@@ -122809,10 +123736,14 @@ async function run(argv, ctxOverride) {
|
|
|
122809
123736
|
cli.version(VERSION);
|
|
122810
123737
|
const command = argv[0] ?? "help";
|
|
122811
123738
|
try {
|
|
122812
|
-
await showTelemetryNotice();
|
|
122813
123739
|
cli.parse(["percher", "percher", ...argv], { run: false });
|
|
122814
123740
|
const requested = argv[0];
|
|
122815
123741
|
if (cli.matchedCommand) {
|
|
123742
|
+
await askTelemetryConsentOnce(ctx, argv, cli.matchedCommand.name, {
|
|
123743
|
+
ask: options.askTelemetry ?? askOnStdin,
|
|
123744
|
+
stderrIsTTY: options.stderrIsTTY ?? process.stderr.isTTY === true,
|
|
123745
|
+
setTimer: options.setTimer
|
|
123746
|
+
});
|
|
122816
123747
|
await cli.runMatchedCommand();
|
|
122817
123748
|
} else if (requested === undefined || requested === "help") {
|
|
122818
123749
|
cli.outputHelp();
|