percher 0.5.5 → 0.5.7
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 +1966 -125
- package/dist/package.json +1 -1
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +86 -14
- package/dist/src/commands/migrate.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/percher.js
CHANGED
|
@@ -5069,11 +5069,11 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
5069
5069
|
};
|
|
5070
5070
|
__awaiter = function(thisArg, _arguments, P, generator) {
|
|
5071
5071
|
function adopt(value) {
|
|
5072
|
-
return value instanceof P ? value : new P(function(
|
|
5073
|
-
|
|
5072
|
+
return value instanceof P ? value : new P(function(resolve6) {
|
|
5073
|
+
resolve6(value);
|
|
5074
5074
|
});
|
|
5075
5075
|
}
|
|
5076
|
-
return new (P || (P = Promise))(function(
|
|
5076
|
+
return new (P || (P = Promise))(function(resolve6, reject) {
|
|
5077
5077
|
function fulfilled(value) {
|
|
5078
5078
|
try {
|
|
5079
5079
|
step(generator.next(value));
|
|
@@ -5089,7 +5089,7 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
5089
5089
|
}
|
|
5090
5090
|
}
|
|
5091
5091
|
function step(result) {
|
|
5092
|
-
result.done ?
|
|
5092
|
+
result.done ? resolve6(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
5093
5093
|
}
|
|
5094
5094
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
5095
5095
|
});
|
|
@@ -5318,14 +5318,14 @@ var require_tslib = __commonJS((exports, module) => {
|
|
|
5318
5318
|
}, i);
|
|
5319
5319
|
function verb(n) {
|
|
5320
5320
|
i[n] = o[n] && function(v) {
|
|
5321
|
-
return new Promise(function(
|
|
5322
|
-
v = o[n](v), settle(
|
|
5321
|
+
return new Promise(function(resolve6, reject) {
|
|
5322
|
+
v = o[n](v), settle(resolve6, reject, v.done, v.value);
|
|
5323
5323
|
});
|
|
5324
5324
|
};
|
|
5325
5325
|
}
|
|
5326
|
-
function settle(
|
|
5326
|
+
function settle(resolve6, reject, d, v) {
|
|
5327
5327
|
Promise.resolve(v).then(function(v2) {
|
|
5328
|
-
|
|
5328
|
+
resolve6({ value: v2, done: d });
|
|
5329
5329
|
}, reject);
|
|
5330
5330
|
}
|
|
5331
5331
|
};
|
|
@@ -8824,7 +8824,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8824
8824
|
}
|
|
8825
8825
|
path = url2.path;
|
|
8826
8826
|
}
|
|
8827
|
-
var
|
|
8827
|
+
var isAbsolute2 = exports.isAbsolute(path);
|
|
8828
8828
|
var parts = path.split(/\/+/);
|
|
8829
8829
|
for (var part, up = 0, i = parts.length - 1;i >= 0; i--) {
|
|
8830
8830
|
part = parts[i];
|
|
@@ -8844,7 +8844,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8844
8844
|
}
|
|
8845
8845
|
path = parts.join("/");
|
|
8846
8846
|
if (path === "") {
|
|
8847
|
-
path =
|
|
8847
|
+
path = isAbsolute2 ? "/" : ".";
|
|
8848
8848
|
}
|
|
8849
8849
|
if (url2) {
|
|
8850
8850
|
url2.path = path;
|
|
@@ -8853,7 +8853,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8853
8853
|
return path;
|
|
8854
8854
|
}
|
|
8855
8855
|
exports.normalize = normalize2;
|
|
8856
|
-
function
|
|
8856
|
+
function join17(aRoot, aPath) {
|
|
8857
8857
|
if (aRoot === "") {
|
|
8858
8858
|
aRoot = ".";
|
|
8859
8859
|
}
|
|
@@ -8885,11 +8885,11 @@ var require_util = __commonJS((exports) => {
|
|
|
8885
8885
|
}
|
|
8886
8886
|
return joined;
|
|
8887
8887
|
}
|
|
8888
|
-
exports.join =
|
|
8888
|
+
exports.join = join17;
|
|
8889
8889
|
exports.isAbsolute = function(aPath) {
|
|
8890
8890
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
8891
8891
|
};
|
|
8892
|
-
function
|
|
8892
|
+
function relative3(aRoot, aPath) {
|
|
8893
8893
|
if (aRoot === "") {
|
|
8894
8894
|
aRoot = ".";
|
|
8895
8895
|
}
|
|
@@ -8908,7 +8908,7 @@ var require_util = __commonJS((exports) => {
|
|
|
8908
8908
|
}
|
|
8909
8909
|
return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
|
|
8910
8910
|
}
|
|
8911
|
-
exports.relative =
|
|
8911
|
+
exports.relative = relative3;
|
|
8912
8912
|
var supportsNullProto = function() {
|
|
8913
8913
|
var obj = Object.create(null);
|
|
8914
8914
|
return !("__proto__" in obj);
|
|
@@ -9058,7 +9058,7 @@ var require_util = __commonJS((exports) => {
|
|
|
9058
9058
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
9059
9059
|
}
|
|
9060
9060
|
}
|
|
9061
|
-
sourceURL =
|
|
9061
|
+
sourceURL = join17(urlGenerate(parsed), sourceURL);
|
|
9062
9062
|
}
|
|
9063
9063
|
return normalize2(sourceURL);
|
|
9064
9064
|
}
|
|
@@ -89384,10 +89384,10 @@ var require_browser = __commonJS((exports) => {
|
|
|
89384
89384
|
text = canvas;
|
|
89385
89385
|
canvas = undefined;
|
|
89386
89386
|
}
|
|
89387
|
-
return new Promise(function(
|
|
89387
|
+
return new Promise(function(resolve9, reject) {
|
|
89388
89388
|
try {
|
|
89389
89389
|
const data2 = QRCode.create(text, opts);
|
|
89390
|
-
|
|
89390
|
+
resolve9(renderFunc(data2, canvas, opts));
|
|
89391
89391
|
} catch (e) {
|
|
89392
89392
|
reject(e);
|
|
89393
89393
|
}
|
|
@@ -89466,11 +89466,11 @@ var require_server = __commonJS((exports) => {
|
|
|
89466
89466
|
}
|
|
89467
89467
|
function render(renderFunc, text, params) {
|
|
89468
89468
|
if (!params.cb) {
|
|
89469
|
-
return new Promise(function(
|
|
89469
|
+
return new Promise(function(resolve9, reject) {
|
|
89470
89470
|
try {
|
|
89471
89471
|
const data2 = QRCode.create(text, params.opts);
|
|
89472
89472
|
return renderFunc(data2, params.opts, function(err, data3) {
|
|
89473
|
-
return err ? reject(err) :
|
|
89473
|
+
return err ? reject(err) : resolve9(data3);
|
|
89474
89474
|
});
|
|
89475
89475
|
} catch (e) {
|
|
89476
89476
|
reject(e);
|
|
@@ -89543,6 +89543,462 @@ var init_qr = __esm(() => {
|
|
|
89543
89543
|
import_qrcode = __toESM(require_server(), 1);
|
|
89544
89544
|
});
|
|
89545
89545
|
|
|
89546
|
+
// ../../node_modules/.bun/isexe@2.0.0/node_modules/isexe/windows.js
|
|
89547
|
+
var require_windows = __commonJS((exports, module) => {
|
|
89548
|
+
module.exports = isexe;
|
|
89549
|
+
isexe.sync = sync;
|
|
89550
|
+
var fs = __require("fs");
|
|
89551
|
+
function checkPathExt(path, options) {
|
|
89552
|
+
var pathext = options.pathExt !== undefined ? options.pathExt : process.env.PATHEXT;
|
|
89553
|
+
if (!pathext) {
|
|
89554
|
+
return true;
|
|
89555
|
+
}
|
|
89556
|
+
pathext = pathext.split(";");
|
|
89557
|
+
if (pathext.indexOf("") !== -1) {
|
|
89558
|
+
return true;
|
|
89559
|
+
}
|
|
89560
|
+
for (var i = 0;i < pathext.length; i++) {
|
|
89561
|
+
var p = pathext[i].toLowerCase();
|
|
89562
|
+
if (p && path.substr(-p.length).toLowerCase() === p) {
|
|
89563
|
+
return true;
|
|
89564
|
+
}
|
|
89565
|
+
}
|
|
89566
|
+
return false;
|
|
89567
|
+
}
|
|
89568
|
+
function checkStat(stat2, path, options) {
|
|
89569
|
+
if (!stat2.isSymbolicLink() && !stat2.isFile()) {
|
|
89570
|
+
return false;
|
|
89571
|
+
}
|
|
89572
|
+
return checkPathExt(path, options);
|
|
89573
|
+
}
|
|
89574
|
+
function isexe(path, options, cb) {
|
|
89575
|
+
fs.stat(path, function(er, stat2) {
|
|
89576
|
+
cb(er, er ? false : checkStat(stat2, path, options));
|
|
89577
|
+
});
|
|
89578
|
+
}
|
|
89579
|
+
function sync(path, options) {
|
|
89580
|
+
return checkStat(fs.statSync(path), path, options);
|
|
89581
|
+
}
|
|
89582
|
+
});
|
|
89583
|
+
|
|
89584
|
+
// ../../node_modules/.bun/isexe@2.0.0/node_modules/isexe/mode.js
|
|
89585
|
+
var require_mode2 = __commonJS((exports, module) => {
|
|
89586
|
+
module.exports = isexe;
|
|
89587
|
+
isexe.sync = sync;
|
|
89588
|
+
var fs = __require("fs");
|
|
89589
|
+
function isexe(path, options, cb) {
|
|
89590
|
+
fs.stat(path, function(er, stat2) {
|
|
89591
|
+
cb(er, er ? false : checkStat(stat2, options));
|
|
89592
|
+
});
|
|
89593
|
+
}
|
|
89594
|
+
function sync(path, options) {
|
|
89595
|
+
return checkStat(fs.statSync(path), options);
|
|
89596
|
+
}
|
|
89597
|
+
function checkStat(stat2, options) {
|
|
89598
|
+
return stat2.isFile() && checkMode(stat2, options);
|
|
89599
|
+
}
|
|
89600
|
+
function checkMode(stat2, options) {
|
|
89601
|
+
var mod = stat2.mode;
|
|
89602
|
+
var uid = stat2.uid;
|
|
89603
|
+
var gid = stat2.gid;
|
|
89604
|
+
var myUid = options.uid !== undefined ? options.uid : process.getuid && process.getuid();
|
|
89605
|
+
var myGid = options.gid !== undefined ? options.gid : process.getgid && process.getgid();
|
|
89606
|
+
var u = parseInt("100", 8);
|
|
89607
|
+
var g = parseInt("010", 8);
|
|
89608
|
+
var o = parseInt("001", 8);
|
|
89609
|
+
var ug = u | g;
|
|
89610
|
+
var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
|
|
89611
|
+
return ret;
|
|
89612
|
+
}
|
|
89613
|
+
});
|
|
89614
|
+
|
|
89615
|
+
// ../../node_modules/.bun/isexe@2.0.0/node_modules/isexe/index.js
|
|
89616
|
+
var require_isexe = __commonJS((exports, module) => {
|
|
89617
|
+
var fs = __require("fs");
|
|
89618
|
+
var core2;
|
|
89619
|
+
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
89620
|
+
core2 = require_windows();
|
|
89621
|
+
} else {
|
|
89622
|
+
core2 = require_mode2();
|
|
89623
|
+
}
|
|
89624
|
+
module.exports = isexe;
|
|
89625
|
+
isexe.sync = sync;
|
|
89626
|
+
function isexe(path, options, cb) {
|
|
89627
|
+
if (typeof options === "function") {
|
|
89628
|
+
cb = options;
|
|
89629
|
+
options = {};
|
|
89630
|
+
}
|
|
89631
|
+
if (!cb) {
|
|
89632
|
+
if (typeof Promise !== "function") {
|
|
89633
|
+
throw new TypeError("callback not provided");
|
|
89634
|
+
}
|
|
89635
|
+
return new Promise(function(resolve9, reject) {
|
|
89636
|
+
isexe(path, options || {}, function(er, is) {
|
|
89637
|
+
if (er) {
|
|
89638
|
+
reject(er);
|
|
89639
|
+
} else {
|
|
89640
|
+
resolve9(is);
|
|
89641
|
+
}
|
|
89642
|
+
});
|
|
89643
|
+
});
|
|
89644
|
+
}
|
|
89645
|
+
core2(path, options || {}, function(er, is) {
|
|
89646
|
+
if (er) {
|
|
89647
|
+
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
89648
|
+
er = null;
|
|
89649
|
+
is = false;
|
|
89650
|
+
}
|
|
89651
|
+
}
|
|
89652
|
+
cb(er, is);
|
|
89653
|
+
});
|
|
89654
|
+
}
|
|
89655
|
+
function sync(path, options) {
|
|
89656
|
+
try {
|
|
89657
|
+
return core2.sync(path, options || {});
|
|
89658
|
+
} catch (er) {
|
|
89659
|
+
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
89660
|
+
return false;
|
|
89661
|
+
} else {
|
|
89662
|
+
throw er;
|
|
89663
|
+
}
|
|
89664
|
+
}
|
|
89665
|
+
}
|
|
89666
|
+
});
|
|
89667
|
+
|
|
89668
|
+
// ../../node_modules/.bun/which@2.0.2/node_modules/which/which.js
|
|
89669
|
+
var require_which = __commonJS((exports, module) => {
|
|
89670
|
+
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
89671
|
+
var path = __require("path");
|
|
89672
|
+
var COLON = isWindows ? ";" : ":";
|
|
89673
|
+
var isexe = require_isexe();
|
|
89674
|
+
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
89675
|
+
var getPathInfo = (cmd, opt) => {
|
|
89676
|
+
const colon = opt.colon || COLON;
|
|
89677
|
+
const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
|
|
89678
|
+
...isWindows ? [process.cwd()] : [],
|
|
89679
|
+
...(opt.path || process.env.PATH || "").split(colon)
|
|
89680
|
+
];
|
|
89681
|
+
const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
|
|
89682
|
+
const pathExt = isWindows ? pathExtExe.split(colon) : [""];
|
|
89683
|
+
if (isWindows) {
|
|
89684
|
+
if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
|
|
89685
|
+
pathExt.unshift("");
|
|
89686
|
+
}
|
|
89687
|
+
return {
|
|
89688
|
+
pathEnv,
|
|
89689
|
+
pathExt,
|
|
89690
|
+
pathExtExe
|
|
89691
|
+
};
|
|
89692
|
+
};
|
|
89693
|
+
var which = (cmd, opt, cb) => {
|
|
89694
|
+
if (typeof opt === "function") {
|
|
89695
|
+
cb = opt;
|
|
89696
|
+
opt = {};
|
|
89697
|
+
}
|
|
89698
|
+
if (!opt)
|
|
89699
|
+
opt = {};
|
|
89700
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
89701
|
+
const found = [];
|
|
89702
|
+
const step = (i) => new Promise((resolve9, reject) => {
|
|
89703
|
+
if (i === pathEnv.length)
|
|
89704
|
+
return opt.all && found.length ? resolve9(found) : reject(getNotFoundError(cmd));
|
|
89705
|
+
const ppRaw = pathEnv[i];
|
|
89706
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
89707
|
+
const pCmd = path.join(pathPart, cmd);
|
|
89708
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
89709
|
+
resolve9(subStep(p, i, 0));
|
|
89710
|
+
});
|
|
89711
|
+
const subStep = (p, i, ii) => new Promise((resolve9, reject) => {
|
|
89712
|
+
if (ii === pathExt.length)
|
|
89713
|
+
return resolve9(step(i + 1));
|
|
89714
|
+
const ext = pathExt[ii];
|
|
89715
|
+
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
89716
|
+
if (!er && is) {
|
|
89717
|
+
if (opt.all)
|
|
89718
|
+
found.push(p + ext);
|
|
89719
|
+
else
|
|
89720
|
+
return resolve9(p + ext);
|
|
89721
|
+
}
|
|
89722
|
+
return resolve9(subStep(p, i, ii + 1));
|
|
89723
|
+
});
|
|
89724
|
+
});
|
|
89725
|
+
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
89726
|
+
};
|
|
89727
|
+
var whichSync = (cmd, opt) => {
|
|
89728
|
+
opt = opt || {};
|
|
89729
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
89730
|
+
const found = [];
|
|
89731
|
+
for (let i = 0;i < pathEnv.length; i++) {
|
|
89732
|
+
const ppRaw = pathEnv[i];
|
|
89733
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
89734
|
+
const pCmd = path.join(pathPart, cmd);
|
|
89735
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
89736
|
+
for (let j = 0;j < pathExt.length; j++) {
|
|
89737
|
+
const cur = p + pathExt[j];
|
|
89738
|
+
try {
|
|
89739
|
+
const is = isexe.sync(cur, { pathExt: pathExtExe });
|
|
89740
|
+
if (is) {
|
|
89741
|
+
if (opt.all)
|
|
89742
|
+
found.push(cur);
|
|
89743
|
+
else
|
|
89744
|
+
return cur;
|
|
89745
|
+
}
|
|
89746
|
+
} catch (ex) {}
|
|
89747
|
+
}
|
|
89748
|
+
}
|
|
89749
|
+
if (opt.all && found.length)
|
|
89750
|
+
return found;
|
|
89751
|
+
if (opt.nothrow)
|
|
89752
|
+
return null;
|
|
89753
|
+
throw getNotFoundError(cmd);
|
|
89754
|
+
};
|
|
89755
|
+
module.exports = which;
|
|
89756
|
+
which.sync = whichSync;
|
|
89757
|
+
});
|
|
89758
|
+
|
|
89759
|
+
// ../../node_modules/.bun/path-key@3.1.1/node_modules/path-key/index.js
|
|
89760
|
+
var require_path_key = __commonJS((exports, module) => {
|
|
89761
|
+
var pathKey = (options = {}) => {
|
|
89762
|
+
const environment = options.env || process.env;
|
|
89763
|
+
const platform = options.platform || process.platform;
|
|
89764
|
+
if (platform !== "win32") {
|
|
89765
|
+
return "PATH";
|
|
89766
|
+
}
|
|
89767
|
+
return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
|
|
89768
|
+
};
|
|
89769
|
+
module.exports = pathKey;
|
|
89770
|
+
module.exports.default = pathKey;
|
|
89771
|
+
});
|
|
89772
|
+
|
|
89773
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
89774
|
+
var require_resolveCommand = __commonJS((exports, module) => {
|
|
89775
|
+
var path = __require("path");
|
|
89776
|
+
var which = require_which();
|
|
89777
|
+
var getPathKey = require_path_key();
|
|
89778
|
+
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
89779
|
+
const env = parsed.options.env || process.env;
|
|
89780
|
+
const cwd = process.cwd();
|
|
89781
|
+
const hasCustomCwd = parsed.options.cwd != null;
|
|
89782
|
+
const shouldSwitchCwd = hasCustomCwd && process.chdir !== undefined && !process.chdir.disabled;
|
|
89783
|
+
if (shouldSwitchCwd) {
|
|
89784
|
+
try {
|
|
89785
|
+
process.chdir(parsed.options.cwd);
|
|
89786
|
+
} catch (err) {}
|
|
89787
|
+
}
|
|
89788
|
+
let resolved;
|
|
89789
|
+
try {
|
|
89790
|
+
resolved = which.sync(parsed.command, {
|
|
89791
|
+
path: env[getPathKey({ env })],
|
|
89792
|
+
pathExt: withoutPathExt ? path.delimiter : undefined
|
|
89793
|
+
});
|
|
89794
|
+
} catch (e) {} finally {
|
|
89795
|
+
if (shouldSwitchCwd) {
|
|
89796
|
+
process.chdir(cwd);
|
|
89797
|
+
}
|
|
89798
|
+
}
|
|
89799
|
+
if (resolved) {
|
|
89800
|
+
resolved = path.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
89801
|
+
}
|
|
89802
|
+
return resolved;
|
|
89803
|
+
}
|
|
89804
|
+
function resolveCommand(parsed) {
|
|
89805
|
+
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
|
|
89806
|
+
}
|
|
89807
|
+
module.exports = resolveCommand;
|
|
89808
|
+
});
|
|
89809
|
+
|
|
89810
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js
|
|
89811
|
+
var require_escape = __commonJS((exports, module) => {
|
|
89812
|
+
var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
|
|
89813
|
+
function escapeCommand(arg) {
|
|
89814
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
89815
|
+
return arg;
|
|
89816
|
+
}
|
|
89817
|
+
function escapeArgument(arg, doubleEscapeMetaChars) {
|
|
89818
|
+
arg = `${arg}`;
|
|
89819
|
+
arg = arg.replace(/(?=(\\+?)?)\1"/g, "$1$1\\\"");
|
|
89820
|
+
arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
89821
|
+
arg = `"${arg}"`;
|
|
89822
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
89823
|
+
if (doubleEscapeMetaChars) {
|
|
89824
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
89825
|
+
}
|
|
89826
|
+
return arg;
|
|
89827
|
+
}
|
|
89828
|
+
exports.command = escapeCommand;
|
|
89829
|
+
exports.argument = escapeArgument;
|
|
89830
|
+
});
|
|
89831
|
+
|
|
89832
|
+
// ../../node_modules/.bun/shebang-regex@3.0.0/node_modules/shebang-regex/index.js
|
|
89833
|
+
var require_shebang_regex = __commonJS((exports, module) => {
|
|
89834
|
+
module.exports = /^#!(.*)/;
|
|
89835
|
+
});
|
|
89836
|
+
|
|
89837
|
+
// ../../node_modules/.bun/shebang-command@2.0.0/node_modules/shebang-command/index.js
|
|
89838
|
+
var require_shebang_command = __commonJS((exports, module) => {
|
|
89839
|
+
var shebangRegex = require_shebang_regex();
|
|
89840
|
+
module.exports = (string4 = "") => {
|
|
89841
|
+
const match = string4.match(shebangRegex);
|
|
89842
|
+
if (!match) {
|
|
89843
|
+
return null;
|
|
89844
|
+
}
|
|
89845
|
+
const [path, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
89846
|
+
const binary = path.split("/").pop();
|
|
89847
|
+
if (binary === "env") {
|
|
89848
|
+
return argument;
|
|
89849
|
+
}
|
|
89850
|
+
return argument ? `${binary} ${argument}` : binary;
|
|
89851
|
+
};
|
|
89852
|
+
});
|
|
89853
|
+
|
|
89854
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
|
|
89855
|
+
var require_readShebang = __commonJS((exports, module) => {
|
|
89856
|
+
var fs = __require("fs");
|
|
89857
|
+
var shebangCommand = require_shebang_command();
|
|
89858
|
+
function readShebang(command) {
|
|
89859
|
+
const size = 150;
|
|
89860
|
+
const buffer = Buffer.alloc(size);
|
|
89861
|
+
let fd;
|
|
89862
|
+
try {
|
|
89863
|
+
fd = fs.openSync(command, "r");
|
|
89864
|
+
fs.readSync(fd, buffer, 0, size, 0);
|
|
89865
|
+
fs.closeSync(fd);
|
|
89866
|
+
} catch (e) {}
|
|
89867
|
+
return shebangCommand(buffer.toString());
|
|
89868
|
+
}
|
|
89869
|
+
module.exports = readShebang;
|
|
89870
|
+
});
|
|
89871
|
+
|
|
89872
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
|
|
89873
|
+
var require_parse2 = __commonJS((exports, module) => {
|
|
89874
|
+
var path = __require("path");
|
|
89875
|
+
var resolveCommand = require_resolveCommand();
|
|
89876
|
+
var escape = require_escape();
|
|
89877
|
+
var readShebang = require_readShebang();
|
|
89878
|
+
var isWin = process.platform === "win32";
|
|
89879
|
+
var isExecutableRegExp = /\.(?:com|exe)$/i;
|
|
89880
|
+
var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
|
|
89881
|
+
function detectShebang(parsed) {
|
|
89882
|
+
parsed.file = resolveCommand(parsed);
|
|
89883
|
+
const shebang = parsed.file && readShebang(parsed.file);
|
|
89884
|
+
if (shebang) {
|
|
89885
|
+
parsed.args.unshift(parsed.file);
|
|
89886
|
+
parsed.command = shebang;
|
|
89887
|
+
return resolveCommand(parsed);
|
|
89888
|
+
}
|
|
89889
|
+
return parsed.file;
|
|
89890
|
+
}
|
|
89891
|
+
function parseNonShell(parsed) {
|
|
89892
|
+
if (!isWin) {
|
|
89893
|
+
return parsed;
|
|
89894
|
+
}
|
|
89895
|
+
const commandFile = detectShebang(parsed);
|
|
89896
|
+
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
89897
|
+
if (parsed.options.forceShell || needsShell) {
|
|
89898
|
+
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
89899
|
+
parsed.command = path.normalize(parsed.command);
|
|
89900
|
+
parsed.command = escape.command(parsed.command);
|
|
89901
|
+
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
|
|
89902
|
+
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
89903
|
+
parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
|
|
89904
|
+
parsed.command = process.env.comspec || "cmd.exe";
|
|
89905
|
+
parsed.options.windowsVerbatimArguments = true;
|
|
89906
|
+
}
|
|
89907
|
+
return parsed;
|
|
89908
|
+
}
|
|
89909
|
+
function parse6(command, args, options) {
|
|
89910
|
+
if (args && !Array.isArray(args)) {
|
|
89911
|
+
options = args;
|
|
89912
|
+
args = null;
|
|
89913
|
+
}
|
|
89914
|
+
args = args ? args.slice(0) : [];
|
|
89915
|
+
options = Object.assign({}, options);
|
|
89916
|
+
const parsed = {
|
|
89917
|
+
command,
|
|
89918
|
+
args,
|
|
89919
|
+
options,
|
|
89920
|
+
file: undefined,
|
|
89921
|
+
original: {
|
|
89922
|
+
command,
|
|
89923
|
+
args
|
|
89924
|
+
}
|
|
89925
|
+
};
|
|
89926
|
+
return options.shell ? parsed : parseNonShell(parsed);
|
|
89927
|
+
}
|
|
89928
|
+
module.exports = parse6;
|
|
89929
|
+
});
|
|
89930
|
+
|
|
89931
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js
|
|
89932
|
+
var require_enoent = __commonJS((exports, module) => {
|
|
89933
|
+
var isWin = process.platform === "win32";
|
|
89934
|
+
function notFoundError(original, syscall) {
|
|
89935
|
+
return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
|
|
89936
|
+
code: "ENOENT",
|
|
89937
|
+
errno: "ENOENT",
|
|
89938
|
+
syscall: `${syscall} ${original.command}`,
|
|
89939
|
+
path: original.command,
|
|
89940
|
+
spawnargs: original.args
|
|
89941
|
+
});
|
|
89942
|
+
}
|
|
89943
|
+
function hookChildProcess(cp, parsed) {
|
|
89944
|
+
if (!isWin) {
|
|
89945
|
+
return;
|
|
89946
|
+
}
|
|
89947
|
+
const originalEmit = cp.emit;
|
|
89948
|
+
cp.emit = function(name, arg1) {
|
|
89949
|
+
if (name === "exit") {
|
|
89950
|
+
const err = verifyENOENT(arg1, parsed);
|
|
89951
|
+
if (err) {
|
|
89952
|
+
return originalEmit.call(cp, "error", err);
|
|
89953
|
+
}
|
|
89954
|
+
}
|
|
89955
|
+
return originalEmit.apply(cp, arguments);
|
|
89956
|
+
};
|
|
89957
|
+
}
|
|
89958
|
+
function verifyENOENT(status, parsed) {
|
|
89959
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
89960
|
+
return notFoundError(parsed.original, "spawn");
|
|
89961
|
+
}
|
|
89962
|
+
return null;
|
|
89963
|
+
}
|
|
89964
|
+
function verifyENOENTSync(status, parsed) {
|
|
89965
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
89966
|
+
return notFoundError(parsed.original, "spawnSync");
|
|
89967
|
+
}
|
|
89968
|
+
return null;
|
|
89969
|
+
}
|
|
89970
|
+
module.exports = {
|
|
89971
|
+
hookChildProcess,
|
|
89972
|
+
verifyENOENT,
|
|
89973
|
+
verifyENOENTSync,
|
|
89974
|
+
notFoundError
|
|
89975
|
+
};
|
|
89976
|
+
});
|
|
89977
|
+
|
|
89978
|
+
// ../../node_modules/.bun/cross-spawn@7.0.6/node_modules/cross-spawn/index.js
|
|
89979
|
+
var require_cross_spawn = __commonJS((exports, module) => {
|
|
89980
|
+
var cp = __require("child_process");
|
|
89981
|
+
var parse6 = require_parse2();
|
|
89982
|
+
var enoent = require_enoent();
|
|
89983
|
+
function spawn(command, args, options) {
|
|
89984
|
+
const parsed = parse6(command, args, options);
|
|
89985
|
+
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
|
|
89986
|
+
enoent.hookChildProcess(spawned, parsed);
|
|
89987
|
+
return spawned;
|
|
89988
|
+
}
|
|
89989
|
+
function spawnSync(command, args, options) {
|
|
89990
|
+
const parsed = parse6(command, args, options);
|
|
89991
|
+
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
|
89992
|
+
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
|
89993
|
+
return result;
|
|
89994
|
+
}
|
|
89995
|
+
module.exports = spawn;
|
|
89996
|
+
module.exports.spawn = spawn;
|
|
89997
|
+
module.exports.sync = spawnSync;
|
|
89998
|
+
module.exports._parse = parse6;
|
|
89999
|
+
module.exports._enoent = enoent;
|
|
90000
|
+
});
|
|
90001
|
+
|
|
89546
90002
|
// ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
89547
90003
|
var require_picocolors = __commonJS((exports, module) => {
|
|
89548
90004
|
var p = process || {};
|
|
@@ -89725,7 +90181,7 @@ __export(exports_prompt_hidden, {
|
|
|
89725
90181
|
});
|
|
89726
90182
|
import { stdin, stdout } from "node:process";
|
|
89727
90183
|
function promptHiddenWithStreams(question, input, output) {
|
|
89728
|
-
return new Promise((
|
|
90184
|
+
return new Promise((resolve9, reject) => {
|
|
89729
90185
|
output.write(`${question} `);
|
|
89730
90186
|
let buf = "";
|
|
89731
90187
|
let done = false;
|
|
@@ -89741,7 +90197,7 @@ function promptHiddenWithStreams(question, input, output) {
|
|
|
89741
90197
|
input.removeListener("error", onError);
|
|
89742
90198
|
output.write(`
|
|
89743
90199
|
`);
|
|
89744
|
-
|
|
90200
|
+
resolve9(buf.replace(/\r$/, ""));
|
|
89745
90201
|
return;
|
|
89746
90202
|
}
|
|
89747
90203
|
buf += ch;
|
|
@@ -89763,7 +90219,7 @@ function promptHiddenWithStreams(question, input, output) {
|
|
|
89763
90219
|
input.removeListener("error", onError);
|
|
89764
90220
|
output.write(`
|
|
89765
90221
|
`);
|
|
89766
|
-
|
|
90222
|
+
resolve9(buf.replace(/\r$/, ""));
|
|
89767
90223
|
};
|
|
89768
90224
|
input.on("data", onData);
|
|
89769
90225
|
input.on("error", onError);
|
|
@@ -89781,7 +90237,7 @@ async function promptHidden(question) {
|
|
|
89781
90237
|
ttyStdin.resume();
|
|
89782
90238
|
ttyStdin.setEncoding("utf8");
|
|
89783
90239
|
try {
|
|
89784
|
-
return await new Promise((
|
|
90240
|
+
return await new Promise((resolve9, reject) => {
|
|
89785
90241
|
stdout.write(`${question} `);
|
|
89786
90242
|
let buf = "";
|
|
89787
90243
|
const onData = (key) => {
|
|
@@ -89791,7 +90247,7 @@ async function promptHidden(question) {
|
|
|
89791
90247
|
ttyStdin.removeListener("data", onData);
|
|
89792
90248
|
stdout.write(`
|
|
89793
90249
|
`);
|
|
89794
|
-
|
|
90250
|
+
resolve9(buf);
|
|
89795
90251
|
return;
|
|
89796
90252
|
}
|
|
89797
90253
|
if (ch === "\x03") {
|
|
@@ -105030,10 +105486,17 @@ function loadConfig() {
|
|
|
105030
105486
|
const envToken = process.env.PERCHER_TOKEN;
|
|
105031
105487
|
return {
|
|
105032
105488
|
apiUrl: envUrl ?? file2.apiUrl ?? DEFAULT_API_URL,
|
|
105033
|
-
token: envToken ?? file2.token ?? null
|
|
105034
|
-
anonClaim: file2.anonClaim ?? null
|
|
105489
|
+
token: envToken ?? file2.token ?? null
|
|
105035
105490
|
};
|
|
105036
105491
|
}
|
|
105492
|
+
function readAnonClaims() {
|
|
105493
|
+
const file2 = readFile2();
|
|
105494
|
+
const claims = { ...file2.anonClaims ?? {} };
|
|
105495
|
+
if (file2.anonClaim?.app && !claims[file2.anonClaim.app]) {
|
|
105496
|
+
claims[file2.anonClaim.app] = file2.anonClaim;
|
|
105497
|
+
}
|
|
105498
|
+
return claims;
|
|
105499
|
+
}
|
|
105037
105500
|
function saveConfig(partial2) {
|
|
105038
105501
|
const p = configPath();
|
|
105039
105502
|
mkdirSync3(dirname3(p), { recursive: true });
|
|
@@ -105043,6 +105506,21 @@ function saveConfig(partial2) {
|
|
|
105043
105506
|
writeFileSync3(tmp, JSON.stringify(merged, null, 2), "utf8");
|
|
105044
105507
|
renameSync(tmp, p);
|
|
105045
105508
|
}
|
|
105509
|
+
function getAnonClaim(app) {
|
|
105510
|
+
return readAnonClaims()[app] ?? null;
|
|
105511
|
+
}
|
|
105512
|
+
function setAnonClaim(state) {
|
|
105513
|
+
const claims = { ...readAnonClaims(), [state.app]: state };
|
|
105514
|
+
saveConfig({ anonClaims: claims, anonClaim: null });
|
|
105515
|
+
}
|
|
105516
|
+
function clearAnonClaim(app) {
|
|
105517
|
+
const claims = { ...readAnonClaims() };
|
|
105518
|
+
delete claims[app];
|
|
105519
|
+
saveConfig({ anonClaims: claims, anonClaim: null });
|
|
105520
|
+
}
|
|
105521
|
+
function listAnonClaimApps() {
|
|
105522
|
+
return Object.keys(readAnonClaims());
|
|
105523
|
+
}
|
|
105046
105524
|
|
|
105047
105525
|
// ../client/dist/errors.js
|
|
105048
105526
|
class PercherApiError extends Error {
|
|
@@ -106078,13 +106556,14 @@ var claimInputSchema = exports_external.object({
|
|
|
106078
106556
|
claimToken: exports_external.string().optional().describe("The one-time claim token returned by the anonymous publish (pcl_…)")
|
|
106079
106557
|
});
|
|
106080
106558
|
async function claim(ctx, input = {}) {
|
|
106081
|
-
const
|
|
106082
|
-
const
|
|
106083
|
-
const
|
|
106559
|
+
const tomlApp = readPercherTomlAppName(ctx.cwd) ?? undefined;
|
|
106560
|
+
const remembered = listAnonClaimApps();
|
|
106561
|
+
const app = input.app ?? tomlApp ?? (remembered.length === 1 ? remembered[0] : undefined);
|
|
106562
|
+
const claimToken = input.claimToken ?? (app ? getAnonClaim(app)?.claimToken ?? undefined : undefined);
|
|
106084
106563
|
if (!app) {
|
|
106085
106564
|
return {
|
|
106086
106565
|
status: "needs_token",
|
|
106087
|
-
summary: "No app to claim. Pass --app (or run from the project that published it) and the claim token."
|
|
106566
|
+
summary: remembered.length > 1 ? `Multiple anonymous apps are remembered (${remembered.join(", ")}). Pass --app to choose one.` : "No app to claim. Pass --app (or run from the project that published it) and the claim token."
|
|
106088
106567
|
};
|
|
106089
106568
|
}
|
|
106090
106569
|
if (!claimToken) {
|
|
@@ -106094,8 +106573,7 @@ async function claim(ctx, input = {}) {
|
|
|
106094
106573
|
};
|
|
106095
106574
|
}
|
|
106096
106575
|
const result = await ctx.client.apps.claim(app, { claimToken });
|
|
106097
|
-
|
|
106098
|
-
saveConfig({ anonClaim: null });
|
|
106576
|
+
clearAnonClaim(app);
|
|
106099
106577
|
return {
|
|
106100
106578
|
status: "claimed",
|
|
106101
106579
|
app: result.name,
|
|
@@ -110410,9 +110888,1332 @@ function collectWarnings2(collections, rlsPolicies, unsupported) {
|
|
|
110410
110888
|
}
|
|
110411
110889
|
return warnings;
|
|
110412
110890
|
}
|
|
110891
|
+
// ../core/dist/commands/migrate-supabase-rewrite.js
|
|
110892
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
110893
|
+
import { dirname as dirname5, join as join18, relative as relative4, resolve as resolve7 } from "node:path";
|
|
110894
|
+
|
|
110895
|
+
// ../core/dist/commands/migrate-supabase-walker.js
|
|
110896
|
+
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
110897
|
+
import { mkdir as mkdir2, readdir, readFile as readFile3, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
110898
|
+
import { dirname as dirname4, isAbsolute as isAbsolute2, join as join17, relative as relative3, resolve as resolve6, sep as sep3 } from "node:path";
|
|
110899
|
+
|
|
110900
|
+
// ../core/dist/commands/migrate-supabase-sdk.js
|
|
110901
|
+
var import_jscodeshift = __toESM(require_core3(), 1);
|
|
110902
|
+
var tsx = import_jscodeshift.default.withParser("tsx");
|
|
110903
|
+
function rewriteSupabaseSdk(input) {
|
|
110904
|
+
const pbName = input.pbIdentifier ?? "pb";
|
|
110905
|
+
const supabaseNames = new Set(input.supabaseIdentifiers ?? ["supabase"]);
|
|
110906
|
+
if (!sourceMentionsSupabase(input.source, supabaseNames)) {
|
|
110907
|
+
return { rewritten: input.source, flags: [], changed: false };
|
|
110908
|
+
}
|
|
110909
|
+
let root;
|
|
110910
|
+
try {
|
|
110911
|
+
root = tsx(input.source);
|
|
110912
|
+
} catch (err) {
|
|
110913
|
+
return {
|
|
110914
|
+
rewritten: input.source,
|
|
110915
|
+
flags: [],
|
|
110916
|
+
changed: false,
|
|
110917
|
+
parseError: err instanceof Error ? err.message : String(err)
|
|
110918
|
+
};
|
|
110919
|
+
}
|
|
110920
|
+
const flags = [];
|
|
110921
|
+
const state = { mutated: false };
|
|
110922
|
+
rewriteAuthCalls(root, supabaseNames, pbName, flags, state);
|
|
110923
|
+
rewriteFromCalls(root, supabaseNames, pbName, flags, state);
|
|
110924
|
+
flagUnsupportedPatterns(root, supabaseNames, flags);
|
|
110925
|
+
if (!state.mutated) {
|
|
110926
|
+
return { rewritten: input.source, flags, changed: false };
|
|
110927
|
+
}
|
|
110928
|
+
return {
|
|
110929
|
+
rewritten: root.toSource({ quote: "double" }),
|
|
110930
|
+
flags,
|
|
110931
|
+
changed: true
|
|
110932
|
+
};
|
|
110933
|
+
}
|
|
110934
|
+
function consumesDataErrorEnvelope(path) {
|
|
110935
|
+
let outer = path.node;
|
|
110936
|
+
let outerParent = path.parent?.node;
|
|
110937
|
+
if (outerParent?.type === "AwaitExpression") {
|
|
110938
|
+
const aw = outerParent;
|
|
110939
|
+
if (aw.argument === path.node) {
|
|
110940
|
+
outer = outerParent;
|
|
110941
|
+
outerParent = path.parent.parent?.node;
|
|
110942
|
+
}
|
|
110943
|
+
}
|
|
110944
|
+
if (!outerParent)
|
|
110945
|
+
return false;
|
|
110946
|
+
if (outerParent.type === "MemberExpression") {
|
|
110947
|
+
const m = outerParent;
|
|
110948
|
+
if (m.object === outer && m.property.type === "Identifier") {
|
|
110949
|
+
const propName = m.property.name;
|
|
110950
|
+
if (propName === "data" || propName === "error")
|
|
110951
|
+
return true;
|
|
110952
|
+
}
|
|
110953
|
+
return false;
|
|
110954
|
+
}
|
|
110955
|
+
if (outerParent.type === "VariableDeclarator") {
|
|
110956
|
+
const v = outerParent;
|
|
110957
|
+
if (v.init === outer && v.id.type === "ObjectPattern") {
|
|
110958
|
+
return objectPatternHasDataOrError(v.id);
|
|
110959
|
+
}
|
|
110960
|
+
return false;
|
|
110961
|
+
}
|
|
110962
|
+
if (outerParent.type === "AssignmentExpression") {
|
|
110963
|
+
const a = outerParent;
|
|
110964
|
+
if (a.right === outer && a.left.type === "ObjectPattern") {
|
|
110965
|
+
return objectPatternHasDataOrError(a.left);
|
|
110966
|
+
}
|
|
110967
|
+
return false;
|
|
110968
|
+
}
|
|
110969
|
+
return false;
|
|
110970
|
+
}
|
|
110971
|
+
function objectPatternHasDataOrError(pattern) {
|
|
110972
|
+
for (const prop of pattern.properties) {
|
|
110973
|
+
if ((prop.type === "Property" || prop.type === "ObjectProperty") && "key" in prop && prop.key.type === "Identifier") {
|
|
110974
|
+
const name = prop.key.name;
|
|
110975
|
+
if (name === "data" || name === "error")
|
|
110976
|
+
return true;
|
|
110977
|
+
}
|
|
110978
|
+
}
|
|
110979
|
+
return false;
|
|
110980
|
+
}
|
|
110981
|
+
function flagEnvelopeManualReview(path, pattern, flags) {
|
|
110982
|
+
flags.push(makeFlag(path, "manual_review", `${pattern}.envelope`, `Call site consumes the Supabase \`{ data, error }\` envelope — PocketBase returns plain values. Skipping rewrite; unwrap the destructure (or .data/.error access) manually, then re-run the migrator.`));
|
|
110983
|
+
}
|
|
110984
|
+
function sourceMentionsSupabase(source, supabaseNames) {
|
|
110985
|
+
if (source.includes("@supabase/supabase-js"))
|
|
110986
|
+
return true;
|
|
110987
|
+
for (const name of supabaseNames) {
|
|
110988
|
+
if (source.includes(name))
|
|
110989
|
+
return true;
|
|
110990
|
+
}
|
|
110991
|
+
return false;
|
|
110992
|
+
}
|
|
110993
|
+
function rewriteAuthCalls(root, supabaseNames, pbName, flags, state) {
|
|
110994
|
+
root.find(import_jscodeshift.default.CallExpression).filter((path) => isSupabaseAuthCall(path, supabaseNames)).forEach((path) => {
|
|
110995
|
+
const callee = path.node.callee;
|
|
110996
|
+
const method = callee.property.name;
|
|
110997
|
+
switch (method) {
|
|
110998
|
+
case "signInWithPassword":
|
|
110999
|
+
replaceAuthSignIn(path, pbName, flags, state);
|
|
111000
|
+
return;
|
|
111001
|
+
case "signUp":
|
|
111002
|
+
replaceAuthSignUp(path, pbName, flags, state);
|
|
111003
|
+
return;
|
|
111004
|
+
case "signOut":
|
|
111005
|
+
replaceAuthSignOut(path, pbName, flags, state);
|
|
111006
|
+
return;
|
|
111007
|
+
case "getUser":
|
|
111008
|
+
replaceAuthGetUser(path, pbName, flags, state);
|
|
111009
|
+
return;
|
|
111010
|
+
case "onAuthStateChange":
|
|
111011
|
+
replaceAuthOnChange(path, pbName, flags, state);
|
|
111012
|
+
return;
|
|
111013
|
+
}
|
|
111014
|
+
});
|
|
111015
|
+
}
|
|
111016
|
+
function replaceAuthOnChange(path, pbName, flags, state) {
|
|
111017
|
+
const callback = path.node.arguments[0];
|
|
111018
|
+
if (!callback) {
|
|
111019
|
+
flags.push(makeFlag(path, "manual_review", "auth.onAuthStateChange", "onAuthStateChange called with no args — manual review."));
|
|
111020
|
+
return;
|
|
111021
|
+
}
|
|
111022
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("authStore")), import_jscodeshift.default.identifier("onChange")), [callback]);
|
|
111023
|
+
applyRewrite(path, replacement, "manual_review", "auth.onAuthStateChange", "onAuthStateChange → pb.authStore.onChange — the callback signature changes: Supabase passes `(event, session)`, PB passes `(token, model)`. Rewrite the callback body.", flags, state);
|
|
111024
|
+
}
|
|
111025
|
+
function isSupabaseAuthCall(path, supabaseNames) {
|
|
111026
|
+
const callee = path.node.callee;
|
|
111027
|
+
if (callee.type !== "MemberExpression")
|
|
111028
|
+
return false;
|
|
111029
|
+
if (callee.property.type !== "Identifier")
|
|
111030
|
+
return false;
|
|
111031
|
+
const object2 = callee.object;
|
|
111032
|
+
if (object2.type !== "MemberExpression")
|
|
111033
|
+
return false;
|
|
111034
|
+
if (object2.property.type !== "Identifier" || object2.property.name !== "auth")
|
|
111035
|
+
return false;
|
|
111036
|
+
if (object2.object.type !== "Identifier")
|
|
111037
|
+
return false;
|
|
111038
|
+
return supabaseNames.has(object2.object.name);
|
|
111039
|
+
}
|
|
111040
|
+
function replaceAuthSignIn(path, pbName, flags, state) {
|
|
111041
|
+
const arg = path.node.arguments[0];
|
|
111042
|
+
if (arg?.type !== "ObjectExpression") {
|
|
111043
|
+
flags.push(makeFlag(path, "manual_review", "auth.signInWithPassword", "auth.signInWithPassword called with non-object argument — manual review needed."));
|
|
111044
|
+
return;
|
|
111045
|
+
}
|
|
111046
|
+
const emailExpr = findObjectProp(arg, "email");
|
|
111047
|
+
const passwordExpr = findObjectProp(arg, "password");
|
|
111048
|
+
if (!emailExpr || !passwordExpr) {
|
|
111049
|
+
flags.push(makeFlag(path, "manual_review", "auth.signInWithPassword", "auth.signInWithPassword object missing email or password — manual review needed."));
|
|
111050
|
+
return;
|
|
111051
|
+
}
|
|
111052
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111053
|
+
flagEnvelopeManualReview(path, "auth.signInWithPassword", flags);
|
|
111054
|
+
return;
|
|
111055
|
+
}
|
|
111056
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal("users")]), import_jscodeshift.default.identifier("authWithPassword")), [emailExpr, passwordExpr]);
|
|
111057
|
+
applyRewrite(path, replacement, "rewritten", "auth.signInWithPassword", 'signInWithPassword → pb.collection("users").authWithPassword', flags, state);
|
|
111058
|
+
}
|
|
111059
|
+
function replaceAuthSignUp(path, pbName, flags, state) {
|
|
111060
|
+
const arg = path.node.arguments[0];
|
|
111061
|
+
if (arg?.type !== "ObjectExpression") {
|
|
111062
|
+
flags.push(makeFlag(path, "manual_review", "auth.signUp", "auth.signUp called with non-object argument — manual review needed."));
|
|
111063
|
+
return;
|
|
111064
|
+
}
|
|
111065
|
+
const emailExpr = findObjectProp(arg, "email");
|
|
111066
|
+
const passwordExpr = findObjectProp(arg, "password");
|
|
111067
|
+
if (!emailExpr || !passwordExpr) {
|
|
111068
|
+
flags.push(makeFlag(path, "manual_review", "auth.signUp", "auth.signUp object missing email or password — manual review needed."));
|
|
111069
|
+
return;
|
|
111070
|
+
}
|
|
111071
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111072
|
+
flagEnvelopeManualReview(path, "auth.signUp", flags);
|
|
111073
|
+
return;
|
|
111074
|
+
}
|
|
111075
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal("users")]), import_jscodeshift.default.identifier("create")), [
|
|
111076
|
+
import_jscodeshift.default.objectExpression([
|
|
111077
|
+
import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("email"), emailExpr),
|
|
111078
|
+
import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("password"), passwordExpr),
|
|
111079
|
+
import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("passwordConfirm"), passwordExpr)
|
|
111080
|
+
])
|
|
111081
|
+
]);
|
|
111082
|
+
applyRewrite(path, replacement, "rewritten", "auth.signUp", 'signUp → pb.collection("users").create({...passwordConfirm})', flags, state);
|
|
111083
|
+
}
|
|
111084
|
+
function replaceAuthSignOut(path, pbName, flags, state) {
|
|
111085
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111086
|
+
flagEnvelopeManualReview(path, "auth.signOut", flags);
|
|
111087
|
+
return;
|
|
111088
|
+
}
|
|
111089
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("authStore")), import_jscodeshift.default.identifier("clear")), []);
|
|
111090
|
+
applyRewrite(path, replacement, "rewritten", "auth.signOut", "signOut → pb.authStore.clear()", flags, state);
|
|
111091
|
+
}
|
|
111092
|
+
function replaceAuthGetUser(path, pbName, flags, state) {
|
|
111093
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111094
|
+
flagEnvelopeManualReview(path, "auth.getUser", flags);
|
|
111095
|
+
return;
|
|
111096
|
+
}
|
|
111097
|
+
const replacement = import_jscodeshift.default.memberExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("authStore")), import_jscodeshift.default.identifier("model"));
|
|
111098
|
+
applyRewrite(path, replacement, "manual_review", "auth.getUser", "getUser → pb.authStore.model — note Supabase returned Promise<{ data: { user } }>, PB returns the record sync; remove awaits + .data.user access.", flags, state);
|
|
111099
|
+
}
|
|
111100
|
+
function rewriteFromCalls(root, supabaseNames, pbName, flags, state) {
|
|
111101
|
+
root.find(import_jscodeshift.default.CallExpression).filter((path) => isSupabaseFromTerminal(path, supabaseNames)).forEach((path) => {
|
|
111102
|
+
rewriteFromChain(path, supabaseNames, pbName, flags, state);
|
|
111103
|
+
});
|
|
111104
|
+
}
|
|
111105
|
+
function isSupabaseFromTerminal(path, supabaseNames) {
|
|
111106
|
+
let fromCall = null;
|
|
111107
|
+
let cursor = path.node;
|
|
111108
|
+
while (cursor.type === "CallExpression") {
|
|
111109
|
+
const call = cursor;
|
|
111110
|
+
if (call.callee.type !== "MemberExpression")
|
|
111111
|
+
break;
|
|
111112
|
+
const callee = call.callee;
|
|
111113
|
+
if (callee.property.type === "Identifier" && callee.property.name === "from") {
|
|
111114
|
+
fromCall = call;
|
|
111115
|
+
break;
|
|
111116
|
+
}
|
|
111117
|
+
cursor = callee.object;
|
|
111118
|
+
}
|
|
111119
|
+
if (!fromCall)
|
|
111120
|
+
return false;
|
|
111121
|
+
const fromCallee = fromCall.callee;
|
|
111122
|
+
if (fromCallee.object.type !== "Identifier")
|
|
111123
|
+
return false;
|
|
111124
|
+
if (!supabaseNames.has(fromCallee.object.name))
|
|
111125
|
+
return false;
|
|
111126
|
+
const parent = path.parent?.node;
|
|
111127
|
+
if (parent?.type === "MemberExpression") {
|
|
111128
|
+
const parentMember = parent;
|
|
111129
|
+
if (parentMember.object === path.node)
|
|
111130
|
+
return false;
|
|
111131
|
+
}
|
|
111132
|
+
return true;
|
|
111133
|
+
}
|
|
111134
|
+
function rewriteFromChain(path, _supabaseNames, pbName, flags, state) {
|
|
111135
|
+
const decomposed = decomposeFromChain(path.node);
|
|
111136
|
+
if (!decomposed) {
|
|
111137
|
+
flags.push(makeFlag(path, "manual_review", "from.chain", "Couldn't decompose .from() chain shape — manual review."));
|
|
111138
|
+
return;
|
|
111139
|
+
}
|
|
111140
|
+
const { table, steps } = decomposed;
|
|
111141
|
+
const terminal = steps[0];
|
|
111142
|
+
if (!terminal) {
|
|
111143
|
+
return;
|
|
111144
|
+
}
|
|
111145
|
+
switch (terminal.method) {
|
|
111146
|
+
case "select":
|
|
111147
|
+
rewriteSelect(path, pbName, table, steps, flags, state);
|
|
111148
|
+
return;
|
|
111149
|
+
case "insert":
|
|
111150
|
+
rewriteInsert(path, pbName, table, terminal, flags, state);
|
|
111151
|
+
return;
|
|
111152
|
+
case "update":
|
|
111153
|
+
rewriteUpdate(path, pbName, table, steps, flags, state);
|
|
111154
|
+
return;
|
|
111155
|
+
case "delete":
|
|
111156
|
+
rewriteDelete(path, pbName, table, steps, flags, state);
|
|
111157
|
+
return;
|
|
111158
|
+
case "upsert":
|
|
111159
|
+
flags.push(makeFlag(path, "unsupported", "from.upsert", `from(${JSON.stringify(table)}).upsert(...) — PB has no upsert primitive. Rewrite as getOne (catch 404) → update-or-create.`));
|
|
111160
|
+
return;
|
|
111161
|
+
default:
|
|
111162
|
+
flags.push(makeFlag(path, "manual_review", `from.${terminal.method}`, `from(${JSON.stringify(table)}).${terminal.method}(...) has no chunk-1 rewrite — manual review.`));
|
|
111163
|
+
}
|
|
111164
|
+
}
|
|
111165
|
+
function decomposeFromChain(outer) {
|
|
111166
|
+
const reversedSteps = [];
|
|
111167
|
+
let node = outer;
|
|
111168
|
+
while (node.type === "CallExpression") {
|
|
111169
|
+
const call = node;
|
|
111170
|
+
if (call.callee.type !== "MemberExpression")
|
|
111171
|
+
break;
|
|
111172
|
+
const callee = call.callee;
|
|
111173
|
+
const method = callee.property.type === "Identifier" ? callee.property.name : null;
|
|
111174
|
+
if (method === null)
|
|
111175
|
+
return null;
|
|
111176
|
+
if (method === "from") {
|
|
111177
|
+
const arg = call.arguments[0];
|
|
111178
|
+
if (!arg || arg.type !== "Literal" && arg.type !== "StringLiteral")
|
|
111179
|
+
return null;
|
|
111180
|
+
const table = arg.value;
|
|
111181
|
+
if (typeof table !== "string")
|
|
111182
|
+
return null;
|
|
111183
|
+
return { table, steps: reversedSteps.reverse() };
|
|
111184
|
+
}
|
|
111185
|
+
reversedSteps.push({ method, args: call.arguments });
|
|
111186
|
+
node = callee.object;
|
|
111187
|
+
}
|
|
111188
|
+
return null;
|
|
111189
|
+
}
|
|
111190
|
+
function rewriteSelect(path, pbName, table, steps, flags, state) {
|
|
111191
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111192
|
+
flagEnvelopeManualReview(path, "from.select", flags);
|
|
111193
|
+
return;
|
|
111194
|
+
}
|
|
111195
|
+
const select = steps[0];
|
|
111196
|
+
if (!select)
|
|
111197
|
+
return;
|
|
111198
|
+
const tail = steps.slice(1);
|
|
111199
|
+
const opts = {};
|
|
111200
|
+
let needsReview = false;
|
|
111201
|
+
const reviewNotes = [];
|
|
111202
|
+
let usePagination = false;
|
|
111203
|
+
let paginationPage = 1;
|
|
111204
|
+
let paginationPerPage = 0;
|
|
111205
|
+
const fieldsValue = extractSelectFields(select);
|
|
111206
|
+
if (fieldsValue !== null)
|
|
111207
|
+
opts.fields = import_jscodeshift.default.literal(fieldsValue);
|
|
111208
|
+
for (const step of tail) {
|
|
111209
|
+
switch (step.method) {
|
|
111210
|
+
case "eq": {
|
|
111211
|
+
const result = buildEqFilter(step);
|
|
111212
|
+
if (!result) {
|
|
111213
|
+
needsReview = true;
|
|
111214
|
+
reviewNotes.push(`.eq() arguments not in the (column-literal, value) shape — manual review.`);
|
|
111215
|
+
continue;
|
|
111216
|
+
}
|
|
111217
|
+
opts.filter = result.identifierValue ? combineFilterDynamic(opts.filter, result.expression) : combineFilterStatic(opts.filter, result.expression);
|
|
111218
|
+
if (result.identifierValue) {
|
|
111219
|
+
needsReview = true;
|
|
111220
|
+
reviewNotes.push(`.eq(${JSON.stringify(result.column)}, <identifier>) — verify the value is escape-safe for PB filter strings (no double-quotes / backslashes).`);
|
|
111221
|
+
}
|
|
111222
|
+
break;
|
|
111223
|
+
}
|
|
111224
|
+
case "order": {
|
|
111225
|
+
const sortFrag = buildSortFragment(step);
|
|
111226
|
+
if (!sortFrag) {
|
|
111227
|
+
needsReview = true;
|
|
111228
|
+
reviewNotes.push(`.order() arguments not in the recognised shape — manual review.`);
|
|
111229
|
+
continue;
|
|
111230
|
+
}
|
|
111231
|
+
opts.sort = import_jscodeshift.default.literal(opts.sort ? `${literalString(opts.sort)},${sortFrag}` : sortFrag);
|
|
111232
|
+
break;
|
|
111233
|
+
}
|
|
111234
|
+
case "limit": {
|
|
111235
|
+
const arg = step.args[0];
|
|
111236
|
+
const n = extractNumber(arg);
|
|
111237
|
+
if (n === null) {
|
|
111238
|
+
needsReview = true;
|
|
111239
|
+
reviewNotes.push(`.limit() argument isn't a literal number — manual review.`);
|
|
111240
|
+
continue;
|
|
111241
|
+
}
|
|
111242
|
+
if (n <= 0) {
|
|
111243
|
+
flags.push(makeFlag(path, "manual_review", "from.select.limit_invalid", `from(${JSON.stringify(table)}).select(...).limit(${n}) — non-positive limit doesn't translate to PB pagination. Manual review.`));
|
|
111244
|
+
return;
|
|
111245
|
+
}
|
|
111246
|
+
usePagination = true;
|
|
111247
|
+
paginationPerPage = Math.max(paginationPerPage, n);
|
|
111248
|
+
break;
|
|
111249
|
+
}
|
|
111250
|
+
case "range": {
|
|
111251
|
+
const startArg = step.args[0];
|
|
111252
|
+
const endArg = step.args[1];
|
|
111253
|
+
const startN = extractNumber(startArg);
|
|
111254
|
+
const endN = extractNumber(endArg);
|
|
111255
|
+
if (startN === null || endN === null) {
|
|
111256
|
+
needsReview = true;
|
|
111257
|
+
reviewNotes.push(`.range() arguments aren't literal numbers — manual review.`);
|
|
111258
|
+
continue;
|
|
111259
|
+
}
|
|
111260
|
+
const perPage = endN - startN + 1;
|
|
111261
|
+
if (perPage <= 0) {
|
|
111262
|
+
flags.push(makeFlag(path, "manual_review", "from.select.range_invalid", `from(${JSON.stringify(table)}).select(...).range(${startN}, ${endN}) — end < start; PB pagination has no equivalent. Manual review.`));
|
|
111263
|
+
return;
|
|
111264
|
+
}
|
|
111265
|
+
usePagination = true;
|
|
111266
|
+
paginationPerPage = Math.max(paginationPerPage, perPage);
|
|
111267
|
+
if (startN === 0) {
|
|
111268
|
+
paginationPage = 1;
|
|
111269
|
+
} else if (startN % perPage === 0) {
|
|
111270
|
+
paginationPage = Math.floor(startN / perPage) + 1;
|
|
111271
|
+
} else {
|
|
111272
|
+
needsReview = true;
|
|
111273
|
+
reviewNotes.push(`.range(${startN}, ${endN}) — start isn't on a page boundary; PB's page math doesn't translate cleanly. Manual review.`);
|
|
111274
|
+
}
|
|
111275
|
+
break;
|
|
111276
|
+
}
|
|
111277
|
+
case "single": {
|
|
111278
|
+
flags.push(makeFlag(path, "manual_review", "from.select.single", `from(${JSON.stringify(table)}).select(...).single() — PB's getFullList returns an array; getFirstListItem(filter) is the single-record equivalent but takes a filter string. Rewrite this chain by hand: pick getFirstListItem with the right filter OR [0]-index the array result.`));
|
|
111279
|
+
return;
|
|
111280
|
+
}
|
|
111281
|
+
default: {
|
|
111282
|
+
flags.push(makeFlag(path, "manual_review", `from.select.${step.method}`, `from(${JSON.stringify(table)}).select(...).${step.method}(...) has no chunk-2 rewrite — manual review.`));
|
|
111283
|
+
return;
|
|
111284
|
+
}
|
|
111285
|
+
}
|
|
111286
|
+
}
|
|
111287
|
+
let methodName;
|
|
111288
|
+
let methodArgs;
|
|
111289
|
+
if (usePagination) {
|
|
111290
|
+
methodName = "getList";
|
|
111291
|
+
const trailingOpts = buildOptionsObject(opts);
|
|
111292
|
+
methodArgs = [import_jscodeshift.default.literal(paginationPage), import_jscodeshift.default.literal(paginationPerPage)];
|
|
111293
|
+
if (trailingOpts)
|
|
111294
|
+
methodArgs.push(trailingOpts);
|
|
111295
|
+
} else {
|
|
111296
|
+
methodName = "getFullList";
|
|
111297
|
+
const optsObj = buildOptionsObject(opts);
|
|
111298
|
+
methodArgs = optsObj ? [optsObj] : [];
|
|
111299
|
+
}
|
|
111300
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal(table)]), import_jscodeshift.default.identifier(methodName)), methodArgs);
|
|
111301
|
+
const kind = needsReview ? "manual_review" : "rewritten";
|
|
111302
|
+
const baseNote = `from(${JSON.stringify(table)}).select(...) → pb.collection(...).${methodName}(...)`;
|
|
111303
|
+
const note = needsReview ? `${baseNote} — ${reviewNotes.join(" · ")}` : baseNote;
|
|
111304
|
+
applyRewrite(path, replacement, kind, "from.select", note, flags, state);
|
|
111305
|
+
}
|
|
111306
|
+
function extractSelectFields(select) {
|
|
111307
|
+
const first = select.args[0];
|
|
111308
|
+
if (!first)
|
|
111309
|
+
return null;
|
|
111310
|
+
if ((first.type === "Literal" || first.type === "StringLiteral") && typeof first.value === "string") {
|
|
111311
|
+
const val = first.value;
|
|
111312
|
+
if (val === "*" || val.length === 0)
|
|
111313
|
+
return null;
|
|
111314
|
+
return val;
|
|
111315
|
+
}
|
|
111316
|
+
return null;
|
|
111317
|
+
}
|
|
111318
|
+
function buildEqFilter(step) {
|
|
111319
|
+
const colArg = step.args[0];
|
|
111320
|
+
const valArg = step.args[1];
|
|
111321
|
+
if (!colArg || !valArg)
|
|
111322
|
+
return null;
|
|
111323
|
+
if (!(colArg.type === "Literal" || colArg.type === "StringLiteral") || typeof colArg.value !== "string") {
|
|
111324
|
+
return null;
|
|
111325
|
+
}
|
|
111326
|
+
const column = colArg.value;
|
|
111327
|
+
if (valArg.type === "Literal" || valArg.type === "StringLiteral" || valArg.type === "NumericLiteral" || valArg.type === "BooleanLiteral") {
|
|
111328
|
+
const v = valArg.value;
|
|
111329
|
+
if (typeof v === "string") {
|
|
111330
|
+
return {
|
|
111331
|
+
expression: import_jscodeshift.default.literal(`${column} = "${escapeFilterString(v)}"`),
|
|
111332
|
+
column,
|
|
111333
|
+
identifierValue: false
|
|
111334
|
+
};
|
|
111335
|
+
}
|
|
111336
|
+
if (typeof v === "number" || typeof v === "boolean") {
|
|
111337
|
+
return {
|
|
111338
|
+
expression: import_jscodeshift.default.literal(`${column} = ${v}`),
|
|
111339
|
+
column,
|
|
111340
|
+
identifierValue: false
|
|
111341
|
+
};
|
|
111342
|
+
}
|
|
111343
|
+
return null;
|
|
111344
|
+
}
|
|
111345
|
+
const template = import_jscodeshift.default.templateLiteral([
|
|
111346
|
+
import_jscodeshift.default.templateElement({ raw: `${column} = "`, cooked: `${column} = "` }, false),
|
|
111347
|
+
import_jscodeshift.default.templateElement({ raw: `"`, cooked: `"` }, true)
|
|
111348
|
+
], [valArg]);
|
|
111349
|
+
return {
|
|
111350
|
+
expression: template,
|
|
111351
|
+
column,
|
|
111352
|
+
identifierValue: true
|
|
111353
|
+
};
|
|
111354
|
+
}
|
|
111355
|
+
function escapeFilterString(s) {
|
|
111356
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
111357
|
+
}
|
|
111358
|
+
function combineFilterStatic(current, next) {
|
|
111359
|
+
if (!current)
|
|
111360
|
+
return next;
|
|
111361
|
+
const a = literalString(current);
|
|
111362
|
+
const b = literalString(next);
|
|
111363
|
+
if (a !== null && b !== null) {
|
|
111364
|
+
return import_jscodeshift.default.literal(`(${a}) && (${b})`);
|
|
111365
|
+
}
|
|
111366
|
+
return combineFilterDynamic(current, next);
|
|
111367
|
+
}
|
|
111368
|
+
function combineFilterDynamic(current, next) {
|
|
111369
|
+
if (!current)
|
|
111370
|
+
return next;
|
|
111371
|
+
return import_jscodeshift.default.templateLiteral([
|
|
111372
|
+
import_jscodeshift.default.templateElement({ raw: "(", cooked: "(" }, false),
|
|
111373
|
+
import_jscodeshift.default.templateElement({ raw: ") && (", cooked: ") && (" }, false),
|
|
111374
|
+
import_jscodeshift.default.templateElement({ raw: ")", cooked: ")" }, true)
|
|
111375
|
+
], [current, next]);
|
|
111376
|
+
}
|
|
111377
|
+
function literalString(node) {
|
|
111378
|
+
if (node?.type === "Literal" || node?.type === "StringLiteral") {
|
|
111379
|
+
const v = node.value;
|
|
111380
|
+
if (typeof v === "string")
|
|
111381
|
+
return v;
|
|
111382
|
+
}
|
|
111383
|
+
return null;
|
|
111384
|
+
}
|
|
111385
|
+
function buildSortFragment(step) {
|
|
111386
|
+
const colArg = step.args[0];
|
|
111387
|
+
if (!colArg)
|
|
111388
|
+
return null;
|
|
111389
|
+
if (!(colArg.type === "Literal" || colArg.type === "StringLiteral") || typeof colArg.value !== "string") {
|
|
111390
|
+
return null;
|
|
111391
|
+
}
|
|
111392
|
+
const column = colArg.value;
|
|
111393
|
+
let ascending = true;
|
|
111394
|
+
if (step.args.length >= 2) {
|
|
111395
|
+
const opts = step.args[1];
|
|
111396
|
+
if (opts?.type === "ObjectExpression") {
|
|
111397
|
+
const ascProp = findObjectProp(opts, "ascending");
|
|
111398
|
+
if (ascProp?.type === "Literal" || ascProp?.type === "BooleanLiteral") {
|
|
111399
|
+
ascending = ascProp.value === true;
|
|
111400
|
+
} else if (ascProp) {
|
|
111401
|
+
return null;
|
|
111402
|
+
}
|
|
111403
|
+
}
|
|
111404
|
+
}
|
|
111405
|
+
return ascending ? column : `-${column}`;
|
|
111406
|
+
}
|
|
111407
|
+
function extractNumber(node) {
|
|
111408
|
+
if (!node)
|
|
111409
|
+
return null;
|
|
111410
|
+
if (node.type === "Literal" || node.type === "NumericLiteral") {
|
|
111411
|
+
const v = node.value;
|
|
111412
|
+
if (typeof v === "number")
|
|
111413
|
+
return v;
|
|
111414
|
+
}
|
|
111415
|
+
if (node.type === "UnaryExpression") {
|
|
111416
|
+
const u = node;
|
|
111417
|
+
if (u.operator === "-") {
|
|
111418
|
+
const inner = extractNumber(u.argument);
|
|
111419
|
+
if (inner !== null)
|
|
111420
|
+
return -inner;
|
|
111421
|
+
}
|
|
111422
|
+
}
|
|
111423
|
+
return null;
|
|
111424
|
+
}
|
|
111425
|
+
function buildOptionsObject(opts) {
|
|
111426
|
+
const props = [];
|
|
111427
|
+
if (opts.fields !== undefined) {
|
|
111428
|
+
props.push(import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("fields"), opts.fields));
|
|
111429
|
+
}
|
|
111430
|
+
if (opts.filter !== undefined) {
|
|
111431
|
+
props.push(import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("filter"), opts.filter));
|
|
111432
|
+
}
|
|
111433
|
+
if (opts.sort !== undefined) {
|
|
111434
|
+
props.push(import_jscodeshift.default.property("init", import_jscodeshift.default.identifier("sort"), opts.sort));
|
|
111435
|
+
}
|
|
111436
|
+
if (props.length === 0)
|
|
111437
|
+
return null;
|
|
111438
|
+
return import_jscodeshift.default.objectExpression(props);
|
|
111439
|
+
}
|
|
111440
|
+
function rewriteInsert(path, pbName, table, insert, flags, state) {
|
|
111441
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111442
|
+
flagEnvelopeManualReview(path, "from.insert", flags);
|
|
111443
|
+
return;
|
|
111444
|
+
}
|
|
111445
|
+
const arg = insert.args[0];
|
|
111446
|
+
if (!arg) {
|
|
111447
|
+
flags.push(makeFlag(path, "manual_review", "from.insert", "from(...).insert() called with no args — manual review."));
|
|
111448
|
+
return;
|
|
111449
|
+
}
|
|
111450
|
+
if (arg.type === "ArrayExpression") {
|
|
111451
|
+
flags.push(makeFlag(path, "manual_review", "from.insert.array", `from(${JSON.stringify(table)}).insert([...]) — PB's create takes one record at a time; wrap in a loop.`));
|
|
111452
|
+
return;
|
|
111453
|
+
}
|
|
111454
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal(table)]), import_jscodeshift.default.identifier("create")), [arg]);
|
|
111455
|
+
applyRewrite(path, replacement, "rewritten", "from.insert", `from(${JSON.stringify(table)}).insert({...}) → pb.collection(...).create({...})`, flags, state);
|
|
111456
|
+
}
|
|
111457
|
+
function rewriteUpdate(path, pbName, table, steps, flags, state) {
|
|
111458
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111459
|
+
flagEnvelopeManualReview(path, "from.update", flags);
|
|
111460
|
+
return;
|
|
111461
|
+
}
|
|
111462
|
+
const update = steps[0];
|
|
111463
|
+
const eq = steps[1];
|
|
111464
|
+
if (steps.length !== 2 || !update || !eq || eq.method !== "eq") {
|
|
111465
|
+
flags.push(makeFlag(path, "manual_review", "from.update.shape", `from(${JSON.stringify(table)}).update(...) chain isn't the .update({...}).eq("id", v) shape — manual review.`));
|
|
111466
|
+
return;
|
|
111467
|
+
}
|
|
111468
|
+
const eqCol = eq.args[0];
|
|
111469
|
+
const eqVal = eq.args[1];
|
|
111470
|
+
if (!eqCol || !eqVal) {
|
|
111471
|
+
flags.push(makeFlag(path, "manual_review", "from.update.eq", "update().eq(...) call missing args — manual review."));
|
|
111472
|
+
return;
|
|
111473
|
+
}
|
|
111474
|
+
if (!((eqCol.type === "Literal" || eqCol.type === "StringLiteral") && eqCol.value === "id")) {
|
|
111475
|
+
flags.push(makeFlag(path, "manual_review", "from.update.eq_non_id", `from(${JSON.stringify(table)}).update().eq() filters on a non-id column — PB's update needs an id; chunk 2 will handle filter-based updates.`));
|
|
111476
|
+
return;
|
|
111477
|
+
}
|
|
111478
|
+
const updateArg = update.args[0];
|
|
111479
|
+
if (!updateArg) {
|
|
111480
|
+
flags.push(makeFlag(path, "manual_review", "from.update", "update() called with no args — manual review."));
|
|
111481
|
+
return;
|
|
111482
|
+
}
|
|
111483
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal(table)]), import_jscodeshift.default.identifier("update")), [eqVal, updateArg]);
|
|
111484
|
+
applyRewrite(path, replacement, "rewritten", "from.update", `from(${JSON.stringify(table)}).update({...}).eq("id", v) → pb.collection(...).update(v, {...})`, flags, state);
|
|
111485
|
+
}
|
|
111486
|
+
function rewriteDelete(path, pbName, table, steps, flags, state) {
|
|
111487
|
+
if (consumesDataErrorEnvelope(path)) {
|
|
111488
|
+
flagEnvelopeManualReview(path, "from.delete", flags);
|
|
111489
|
+
return;
|
|
111490
|
+
}
|
|
111491
|
+
const eq = steps[1];
|
|
111492
|
+
if (steps.length !== 2 || !eq || eq.method !== "eq") {
|
|
111493
|
+
flags.push(makeFlag(path, "manual_review", "from.delete.shape", `from(${JSON.stringify(table)}).delete() chain isn't the .delete().eq("id", v) shape — manual review.`));
|
|
111494
|
+
return;
|
|
111495
|
+
}
|
|
111496
|
+
const eqCol = eq.args[0];
|
|
111497
|
+
const eqVal = eq.args[1];
|
|
111498
|
+
if (!eqCol || !eqVal) {
|
|
111499
|
+
flags.push(makeFlag(path, "manual_review", "from.delete.eq", "delete().eq(...) call missing args — manual review."));
|
|
111500
|
+
return;
|
|
111501
|
+
}
|
|
111502
|
+
if (!((eqCol.type === "Literal" || eqCol.type === "StringLiteral") && eqCol.value === "id")) {
|
|
111503
|
+
flags.push(makeFlag(path, "manual_review", "from.delete.eq_non_id", `from(${JSON.stringify(table)}).delete().eq() filters on a non-id column — PB's delete needs an id; chunk 2 will handle filter-based deletes.`));
|
|
111504
|
+
return;
|
|
111505
|
+
}
|
|
111506
|
+
const replacement = import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.callExpression(import_jscodeshift.default.memberExpression(import_jscodeshift.default.identifier(pbName), import_jscodeshift.default.identifier("collection")), [import_jscodeshift.default.literal(table)]), import_jscodeshift.default.identifier("delete")), [eqVal]);
|
|
111507
|
+
applyRewrite(path, replacement, "rewritten", "from.delete", `from(${JSON.stringify(table)}).delete().eq("id", v) → pb.collection(...).delete(v)`, flags, state);
|
|
111508
|
+
}
|
|
111509
|
+
function flagUnsupportedPatterns(root, supabaseNames, flags) {
|
|
111510
|
+
root.find(import_jscodeshift.default.CallExpression).forEach((path) => {
|
|
111511
|
+
flagOneUnsupported(path, supabaseNames, flags);
|
|
111512
|
+
});
|
|
111513
|
+
}
|
|
111514
|
+
function flagOneUnsupported(path, supabaseNames, flags) {
|
|
111515
|
+
const root = findChainRoot(path.node);
|
|
111516
|
+
if (!root)
|
|
111517
|
+
return;
|
|
111518
|
+
if (root.type !== "Identifier")
|
|
111519
|
+
return;
|
|
111520
|
+
if (!supabaseNames.has(root.name))
|
|
111521
|
+
return;
|
|
111522
|
+
const parent = path.parent?.node;
|
|
111523
|
+
if (parent?.type === "MemberExpression") {
|
|
111524
|
+
const m = parent;
|
|
111525
|
+
if (m.object === path.node)
|
|
111526
|
+
return;
|
|
111527
|
+
}
|
|
111528
|
+
const steps = readChainSteps(path.node);
|
|
111529
|
+
const first = steps[0];
|
|
111530
|
+
if (!first)
|
|
111531
|
+
return;
|
|
111532
|
+
if (first.method === "storage") {
|
|
111533
|
+
const opStep = findStorageOperation(steps);
|
|
111534
|
+
const opName = opStep?.method ?? "from";
|
|
111535
|
+
flags.push(makeFlag(path, "unsupported", `storage.${opName}`, `supabase.storage.<bucket>.${opName}(...) — PocketBase models files as record-attached fields, not standalone buckets. Rewrite by hand: create a collection with a \`file\` field, then use pb.collection(c).create({ file: blob }) for uploads and pb.files.getURL(record, record.file) for URLs.`));
|
|
111536
|
+
return;
|
|
111537
|
+
}
|
|
111538
|
+
if (first.method === "channel") {
|
|
111539
|
+
flags.push(makeFlag(path, "unsupported", "channel.subscribe", `supabase.channel(...).on(...).subscribe(...) — PB has realtime via pb.collection(c).subscribe("*", cb) but the event shape and filter model differ from Supabase channels. Rewrite by hand.`));
|
|
111540
|
+
return;
|
|
111541
|
+
}
|
|
111542
|
+
if (first.method === "rpc") {
|
|
111543
|
+
const fnName = first.call ? readFirstStringArg(first.call) ?? "<unknown>" : "<unknown>";
|
|
111544
|
+
flags.push(makeFlag(path, "unsupported", "rpc", `supabase.rpc(${JSON.stringify(fnName)}, ...) — Postgres function calls don't have a PocketBase equivalent. Move the logic into your app server code OR a PB hook (.pb_hooks/).`));
|
|
111545
|
+
return;
|
|
111546
|
+
}
|
|
111547
|
+
const invokeStep = steps[1];
|
|
111548
|
+
if (first.method === "functions" && invokeStep?.method === "invoke") {
|
|
111549
|
+
const fnName = invokeStep.call ? readFirstStringArg(invokeStep.call) ?? "<unknown>" : "<unknown>";
|
|
111550
|
+
flags.push(makeFlag(path, "unsupported", "functions.invoke", `supabase.functions.invoke(${JSON.stringify(fnName)}, ...) — Edge Functions don't run on Percher. Move the function code into the Percher app server, or host it on a separate platform (Deno Deploy, Cloudflare Workers) and call it via fetch.`));
|
|
111551
|
+
return;
|
|
111552
|
+
}
|
|
111553
|
+
}
|
|
111554
|
+
var STORAGE_OPERATIONS = new Set([
|
|
111555
|
+
"upload",
|
|
111556
|
+
"uploadToSignedUrl",
|
|
111557
|
+
"download",
|
|
111558
|
+
"list",
|
|
111559
|
+
"remove",
|
|
111560
|
+
"move",
|
|
111561
|
+
"copy",
|
|
111562
|
+
"createSignedUrl",
|
|
111563
|
+
"createSignedUrls",
|
|
111564
|
+
"createSignedUploadUrl",
|
|
111565
|
+
"getPublicUrl",
|
|
111566
|
+
"update",
|
|
111567
|
+
"exists",
|
|
111568
|
+
"info"
|
|
111569
|
+
]);
|
|
111570
|
+
var CHAIN_CONTINUATIONS = new Set(["then", "catch", "finally"]);
|
|
111571
|
+
function findStorageOperation(steps) {
|
|
111572
|
+
for (const step of steps) {
|
|
111573
|
+
if (STORAGE_OPERATIONS.has(step.method))
|
|
111574
|
+
return step;
|
|
111575
|
+
}
|
|
111576
|
+
for (let i = steps.length - 1;i >= 0; i--) {
|
|
111577
|
+
const step = steps[i];
|
|
111578
|
+
if (!step)
|
|
111579
|
+
continue;
|
|
111580
|
+
if (step.method === "storage" || step.method === "from")
|
|
111581
|
+
continue;
|
|
111582
|
+
if (CHAIN_CONTINUATIONS.has(step.method))
|
|
111583
|
+
continue;
|
|
111584
|
+
return step;
|
|
111585
|
+
}
|
|
111586
|
+
return null;
|
|
111587
|
+
}
|
|
111588
|
+
function findChainRoot(node) {
|
|
111589
|
+
let cursor = node;
|
|
111590
|
+
while (true) {
|
|
111591
|
+
if (cursor.type === "CallExpression") {
|
|
111592
|
+
const c = cursor;
|
|
111593
|
+
if (c.callee.type !== "MemberExpression")
|
|
111594
|
+
return null;
|
|
111595
|
+
cursor = c.callee.object;
|
|
111596
|
+
continue;
|
|
111597
|
+
}
|
|
111598
|
+
if (cursor.type === "MemberExpression") {
|
|
111599
|
+
cursor = cursor.object;
|
|
111600
|
+
continue;
|
|
111601
|
+
}
|
|
111602
|
+
return cursor;
|
|
111603
|
+
}
|
|
111604
|
+
}
|
|
111605
|
+
function readChainSteps(outer) {
|
|
111606
|
+
const reversed = [];
|
|
111607
|
+
let cursor = outer;
|
|
111608
|
+
while (true) {
|
|
111609
|
+
if (cursor.type === "CallExpression") {
|
|
111610
|
+
const call = cursor;
|
|
111611
|
+
if (call.callee.type !== "MemberExpression")
|
|
111612
|
+
break;
|
|
111613
|
+
const callee = call.callee;
|
|
111614
|
+
if (callee.property.type === "Identifier") {
|
|
111615
|
+
reversed.push({
|
|
111616
|
+
method: callee.property.name,
|
|
111617
|
+
call
|
|
111618
|
+
});
|
|
111619
|
+
}
|
|
111620
|
+
cursor = callee.object;
|
|
111621
|
+
continue;
|
|
111622
|
+
}
|
|
111623
|
+
if (cursor.type === "MemberExpression") {
|
|
111624
|
+
const m = cursor;
|
|
111625
|
+
if (m.property.type === "Identifier") {
|
|
111626
|
+
reversed.push({
|
|
111627
|
+
method: m.property.name,
|
|
111628
|
+
call: null
|
|
111629
|
+
});
|
|
111630
|
+
}
|
|
111631
|
+
cursor = m.object;
|
|
111632
|
+
continue;
|
|
111633
|
+
}
|
|
111634
|
+
break;
|
|
111635
|
+
}
|
|
111636
|
+
return reversed.reverse();
|
|
111637
|
+
}
|
|
111638
|
+
function readFirstStringArg(call) {
|
|
111639
|
+
const a = call.arguments[0];
|
|
111640
|
+
if (!a)
|
|
111641
|
+
return null;
|
|
111642
|
+
if (a.type === "Literal" || a.type === "StringLiteral") {
|
|
111643
|
+
const v = a.value;
|
|
111644
|
+
if (typeof v === "string")
|
|
111645
|
+
return v;
|
|
111646
|
+
}
|
|
111647
|
+
return null;
|
|
111648
|
+
}
|
|
111649
|
+
function findObjectProp(obj, name) {
|
|
111650
|
+
for (const prop of obj.properties) {
|
|
111651
|
+
if ((prop.type === "Property" || prop.type === "ObjectProperty") && "key" in prop && prop.key.type === "Identifier" && prop.key.name === name) {
|
|
111652
|
+
if (prop.shorthand === true) {
|
|
111653
|
+
return import_jscodeshift.default.identifier(name);
|
|
111654
|
+
}
|
|
111655
|
+
if ("value" in prop) {
|
|
111656
|
+
const val = prop.value;
|
|
111657
|
+
if (val.type !== "SpreadElement" && val.type !== "RestElement") {
|
|
111658
|
+
return val;
|
|
111659
|
+
}
|
|
111660
|
+
}
|
|
111661
|
+
}
|
|
111662
|
+
}
|
|
111663
|
+
return null;
|
|
111664
|
+
}
|
|
111665
|
+
function makeFlag(pathOrLoc, kind, pattern, note) {
|
|
111666
|
+
let line;
|
|
111667
|
+
let column;
|
|
111668
|
+
if ("node" in pathOrLoc) {
|
|
111669
|
+
const loc = pathOrLoc.node.loc;
|
|
111670
|
+
line = loc?.start.line;
|
|
111671
|
+
column = loc?.start.column;
|
|
111672
|
+
} else {
|
|
111673
|
+
line = pathOrLoc.line;
|
|
111674
|
+
column = pathOrLoc.column;
|
|
111675
|
+
}
|
|
111676
|
+
return { kind, pattern, line, column, note };
|
|
111677
|
+
}
|
|
111678
|
+
function captureLoc(path) {
|
|
111679
|
+
const loc = path.node.loc;
|
|
111680
|
+
return { line: loc?.start.line, column: loc?.start.column };
|
|
111681
|
+
}
|
|
111682
|
+
function applyRewrite(path, replacement, kind, pattern, note, flags, state) {
|
|
111683
|
+
const loc = captureLoc(path);
|
|
111684
|
+
path.replace(replacement);
|
|
111685
|
+
flags.push(makeFlag(loc, kind, pattern, note));
|
|
111686
|
+
state.mutated = true;
|
|
111687
|
+
}
|
|
111688
|
+
|
|
111689
|
+
// ../core/dist/commands/migrate-supabase-walker.js
|
|
111690
|
+
var REWRITABLE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
111691
|
+
var DEFAULT_EXCLUDES = [
|
|
111692
|
+
"node_modules",
|
|
111693
|
+
".git",
|
|
111694
|
+
"dist",
|
|
111695
|
+
"build",
|
|
111696
|
+
".next",
|
|
111697
|
+
".svelte-kit",
|
|
111698
|
+
".astro",
|
|
111699
|
+
".nuxt",
|
|
111700
|
+
".output",
|
|
111701
|
+
"coverage",
|
|
111702
|
+
".bun",
|
|
111703
|
+
".cache",
|
|
111704
|
+
".turbo",
|
|
111705
|
+
"migration-preview",
|
|
111706
|
+
"pb_data",
|
|
111707
|
+
"pb_migrations"
|
|
111708
|
+
];
|
|
111709
|
+
async function walkSupabaseProject(input) {
|
|
111710
|
+
const rootAbs = resolve6(input.rootDir);
|
|
111711
|
+
const ig = import_ignore3.default().add(DEFAULT_EXCLUDES);
|
|
111712
|
+
if (input.extraExcludes && input.extraExcludes.length > 0) {
|
|
111713
|
+
ig.add(input.extraExcludes);
|
|
111714
|
+
}
|
|
111715
|
+
const files = [];
|
|
111716
|
+
const skipped = [];
|
|
111717
|
+
for await (const absPath of walkTree(rootAbs, rootAbs, ig)) {
|
|
111718
|
+
const rel = relative3(rootAbs, absPath).split(sep3).join("/");
|
|
111719
|
+
const kind = classifyFile2(rel);
|
|
111720
|
+
if (kind === null)
|
|
111721
|
+
continue;
|
|
111722
|
+
let source;
|
|
111723
|
+
try {
|
|
111724
|
+
source = await readFile3(absPath, "utf8");
|
|
111725
|
+
} catch (err) {
|
|
111726
|
+
skipped.push({
|
|
111727
|
+
relativePath: rel,
|
|
111728
|
+
reason: "read_error",
|
|
111729
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
111730
|
+
});
|
|
111731
|
+
continue;
|
|
111732
|
+
}
|
|
111733
|
+
if (looksBinary(source)) {
|
|
111734
|
+
skipped.push({ relativePath: rel, reason: "binary" });
|
|
111735
|
+
continue;
|
|
111736
|
+
}
|
|
111737
|
+
if (kind === "code") {
|
|
111738
|
+
const sdkResult = rewriteSupabaseSdk({
|
|
111739
|
+
source,
|
|
111740
|
+
filePath: rel,
|
|
111741
|
+
pbIdentifier: input.pbIdentifier,
|
|
111742
|
+
supabaseIdentifiers: input.supabaseIdentifiers
|
|
111743
|
+
});
|
|
111744
|
+
if (sdkResult.parseError !== undefined) {
|
|
111745
|
+
skipped.push({
|
|
111746
|
+
relativePath: rel,
|
|
111747
|
+
reason: "parse_error",
|
|
111748
|
+
detail: sdkResult.parseError
|
|
111749
|
+
});
|
|
111750
|
+
continue;
|
|
111751
|
+
}
|
|
111752
|
+
files.push({
|
|
111753
|
+
relativePath: rel,
|
|
111754
|
+
kind,
|
|
111755
|
+
source,
|
|
111756
|
+
rewritten: sdkResult.rewritten,
|
|
111757
|
+
changed: sdkResult.changed,
|
|
111758
|
+
flags: sdkResult.flags
|
|
111759
|
+
});
|
|
111760
|
+
continue;
|
|
111761
|
+
}
|
|
111762
|
+
const configResult = kind === "package_json" ? rewritePackageJson(source) : rewriteEnvFile(source);
|
|
111763
|
+
files.push({
|
|
111764
|
+
relativePath: rel,
|
|
111765
|
+
kind,
|
|
111766
|
+
source,
|
|
111767
|
+
rewritten: configResult.rewritten,
|
|
111768
|
+
changed: configResult.changed,
|
|
111769
|
+
flags: configResult.flags
|
|
111770
|
+
});
|
|
111771
|
+
}
|
|
111772
|
+
const flagsByPattern = {};
|
|
111773
|
+
let flagCount = 0;
|
|
111774
|
+
let changedFiles = 0;
|
|
111775
|
+
let packageJsonChanged = false;
|
|
111776
|
+
let envFilesChanged = 0;
|
|
111777
|
+
for (const file2 of files) {
|
|
111778
|
+
if (file2.changed) {
|
|
111779
|
+
changedFiles += 1;
|
|
111780
|
+
if (file2.kind === "package_json")
|
|
111781
|
+
packageJsonChanged = true;
|
|
111782
|
+
if (file2.kind === "env")
|
|
111783
|
+
envFilesChanged += 1;
|
|
111784
|
+
}
|
|
111785
|
+
for (const flag of file2.flags) {
|
|
111786
|
+
flagCount += 1;
|
|
111787
|
+
flagsByPattern[flag.pattern] = (flagsByPattern[flag.pattern] ?? 0) + 1;
|
|
111788
|
+
}
|
|
111789
|
+
}
|
|
111790
|
+
return {
|
|
111791
|
+
files,
|
|
111792
|
+
skipped,
|
|
111793
|
+
flagsByPattern,
|
|
111794
|
+
summary: {
|
|
111795
|
+
totalFiles: files.length,
|
|
111796
|
+
changedFiles,
|
|
111797
|
+
flagCount,
|
|
111798
|
+
packageJsonChanged,
|
|
111799
|
+
envFilesChanged
|
|
111800
|
+
}
|
|
111801
|
+
};
|
|
111802
|
+
}
|
|
111803
|
+
async function* walkTree(dir, rootAbs, ig) {
|
|
111804
|
+
let entries;
|
|
111805
|
+
try {
|
|
111806
|
+
entries = await readdir(dir);
|
|
111807
|
+
} catch {
|
|
111808
|
+
return;
|
|
111809
|
+
}
|
|
111810
|
+
for (const name of entries) {
|
|
111811
|
+
const abs = join17(dir, name);
|
|
111812
|
+
const rel = relative3(rootAbs, abs).split(sep3).join("/");
|
|
111813
|
+
if (rel.length > 0 && ig.ignores(rel))
|
|
111814
|
+
continue;
|
|
111815
|
+
let st;
|
|
111816
|
+
try {
|
|
111817
|
+
st = await stat(abs);
|
|
111818
|
+
} catch {
|
|
111819
|
+
continue;
|
|
111820
|
+
}
|
|
111821
|
+
if (st.isDirectory()) {
|
|
111822
|
+
if (ig.ignores(`${rel}/`))
|
|
111823
|
+
continue;
|
|
111824
|
+
yield* walkTree(abs, rootAbs, ig);
|
|
111825
|
+
continue;
|
|
111826
|
+
}
|
|
111827
|
+
if (st.isFile()) {
|
|
111828
|
+
yield abs;
|
|
111829
|
+
}
|
|
111830
|
+
}
|
|
111831
|
+
}
|
|
111832
|
+
function classifyFile2(relPath) {
|
|
111833
|
+
const base = relPath.split("/").pop() ?? relPath;
|
|
111834
|
+
if (base === "package.json")
|
|
111835
|
+
return "package_json";
|
|
111836
|
+
if (base === ".env" || base.startsWith(".env."))
|
|
111837
|
+
return "env";
|
|
111838
|
+
const dot = base.lastIndexOf(".");
|
|
111839
|
+
if (dot < 0)
|
|
111840
|
+
return null;
|
|
111841
|
+
const ext = base.slice(dot);
|
|
111842
|
+
if (REWRITABLE_EXTENSIONS.has(ext))
|
|
111843
|
+
return "code";
|
|
111844
|
+
return null;
|
|
111845
|
+
}
|
|
111846
|
+
function looksBinary(source) {
|
|
111847
|
+
const limit = Math.min(source.length, 8192);
|
|
111848
|
+
for (let i = 0;i < limit; i++) {
|
|
111849
|
+
if (source.charCodeAt(i) === 0)
|
|
111850
|
+
return true;
|
|
111851
|
+
}
|
|
111852
|
+
return false;
|
|
111853
|
+
}
|
|
111854
|
+
function rewritePackageJson(source) {
|
|
111855
|
+
let pkg;
|
|
111856
|
+
try {
|
|
111857
|
+
pkg = JSON.parse(source);
|
|
111858
|
+
} catch {
|
|
111859
|
+
return { rewritten: source, changed: false, flags: [] };
|
|
111860
|
+
}
|
|
111861
|
+
const depSections = [
|
|
111862
|
+
"dependencies",
|
|
111863
|
+
"devDependencies",
|
|
111864
|
+
"peerDependencies",
|
|
111865
|
+
"optionalDependencies"
|
|
111866
|
+
];
|
|
111867
|
+
let changed = false;
|
|
111868
|
+
const flags = [];
|
|
111869
|
+
for (const section of depSections) {
|
|
111870
|
+
const deps = pkg[section];
|
|
111871
|
+
if (!deps || typeof deps !== "object" || Array.isArray(deps))
|
|
111872
|
+
continue;
|
|
111873
|
+
const depsObj = deps;
|
|
111874
|
+
if ("@supabase/supabase-js" in depsObj) {
|
|
111875
|
+
delete depsObj["@supabase/supabase-js"];
|
|
111876
|
+
if (!("pocketbase" in depsObj)) {
|
|
111877
|
+
depsObj.pocketbase = "^0.21.0";
|
|
111878
|
+
}
|
|
111879
|
+
changed = true;
|
|
111880
|
+
flags.push({
|
|
111881
|
+
kind: "rewritten",
|
|
111882
|
+
pattern: `package.${section}`,
|
|
111883
|
+
note: `${section}: @supabase/supabase-js → pocketbase`
|
|
111884
|
+
});
|
|
111885
|
+
}
|
|
111886
|
+
}
|
|
111887
|
+
if (!changed) {
|
|
111888
|
+
return { rewritten: source, changed: false, flags: [] };
|
|
111889
|
+
}
|
|
111890
|
+
const rewritten = `${JSON.stringify(pkg, null, 2)}
|
|
111891
|
+
`;
|
|
111892
|
+
return { rewritten, changed: true, flags };
|
|
111893
|
+
}
|
|
111894
|
+
function rewriteEnvFile(source) {
|
|
111895
|
+
const lines = source.split(/\r?\n/);
|
|
111896
|
+
const flags = [];
|
|
111897
|
+
const seenPrefixes = new Set;
|
|
111898
|
+
const outLines = [];
|
|
111899
|
+
let changed = false;
|
|
111900
|
+
const HEADER_MARKER = "# === Percher migration: Supabase → PocketBase ===";
|
|
111901
|
+
if (source.includes(HEADER_MARKER)) {
|
|
111902
|
+
return { rewritten: source, changed: false, flags: [] };
|
|
111903
|
+
}
|
|
111904
|
+
for (const [i, line] of lines.entries()) {
|
|
111905
|
+
const match = line.match(/^\s*([A-Z][A-Z0-9_]*)\s*=(.*)$/);
|
|
111906
|
+
if (!match) {
|
|
111907
|
+
outLines.push(line);
|
|
111908
|
+
continue;
|
|
111909
|
+
}
|
|
111910
|
+
const key = match[1] ?? "";
|
|
111911
|
+
if (!key.includes("SUPABASE")) {
|
|
111912
|
+
outLines.push(line);
|
|
111913
|
+
continue;
|
|
111914
|
+
}
|
|
111915
|
+
const prefix = extractPublicPrefix(key);
|
|
111916
|
+
seenPrefixes.add(prefix);
|
|
111917
|
+
outLines.push(`# was: ${line.trim()}`);
|
|
111918
|
+
flags.push({
|
|
111919
|
+
kind: "rewritten",
|
|
111920
|
+
pattern: "env.supabase_key",
|
|
111921
|
+
line: i + 1,
|
|
111922
|
+
note: `${key} commented out — replace with the appropriate POCKETBASE_URL value.`
|
|
111923
|
+
});
|
|
111924
|
+
changed = true;
|
|
111925
|
+
}
|
|
111926
|
+
if (!changed) {
|
|
111927
|
+
return { rewritten: source, changed: false, flags: [] };
|
|
111928
|
+
}
|
|
111929
|
+
const stubLines = [];
|
|
111930
|
+
stubLines.push(HEADER_MARKER);
|
|
111931
|
+
stubLines.push("# Old SUPABASE_* keys are kept above as `# was:` comments.");
|
|
111932
|
+
stubLines.push("# Fill in the POCKETBASE_URL values below and remove the comments");
|
|
111933
|
+
stubLines.push("# once you've verified the migration.");
|
|
111934
|
+
for (const prefix of [...seenPrefixes].sort()) {
|
|
111935
|
+
const pbKey = prefix ? `${prefix}POCKETBASE_URL` : "POCKETBASE_URL";
|
|
111936
|
+
stubLines.push(`${pbKey}=`);
|
|
111937
|
+
}
|
|
111938
|
+
stubLines.push("");
|
|
111939
|
+
const rewritten = `${stubLines.join(`
|
|
111940
|
+
`)}
|
|
111941
|
+
${outLines.join(`
|
|
111942
|
+
`)}`;
|
|
111943
|
+
return { rewritten, changed: true, flags };
|
|
111944
|
+
}
|
|
111945
|
+
function extractPublicPrefix(key) {
|
|
111946
|
+
for (const p of [
|
|
111947
|
+
"NEXT_PUBLIC_",
|
|
111948
|
+
"VITE_",
|
|
111949
|
+
"NUXT_PUBLIC_",
|
|
111950
|
+
"PUBLIC_",
|
|
111951
|
+
"REACT_APP_",
|
|
111952
|
+
"VUE_APP_",
|
|
111953
|
+
"EXPO_PUBLIC_"
|
|
111954
|
+
]) {
|
|
111955
|
+
if (key.startsWith(p))
|
|
111956
|
+
return p;
|
|
111957
|
+
}
|
|
111958
|
+
return "";
|
|
111959
|
+
}
|
|
111960
|
+
async function writeWalkResult(input) {
|
|
111961
|
+
const targetAbs = resolve6(input.targetDir);
|
|
111962
|
+
const changedOnly = input.changedOnly !== false;
|
|
111963
|
+
const written = [];
|
|
111964
|
+
for (const file2 of input.result.files) {
|
|
111965
|
+
if (changedOnly && !file2.changed)
|
|
111966
|
+
continue;
|
|
111967
|
+
const abs = resolve6(targetAbs, file2.relativePath);
|
|
111968
|
+
const rel = relative3(targetAbs, abs);
|
|
111969
|
+
const isParentTraversal = rel === ".." || rel.startsWith(`..${sep3}`) || rel.startsWith("../");
|
|
111970
|
+
if (rel.length === 0 || isParentTraversal || isAbsolute2(rel)) {
|
|
111971
|
+
throw new Error(`writeWalkResult refused path-traversing file "${file2.relativePath}" → "${abs}" (would escape targetDir "${targetAbs}").`);
|
|
111972
|
+
}
|
|
111973
|
+
await mkdir2(dirname4(abs), { recursive: true });
|
|
111974
|
+
await writeFile2(abs, file2.rewritten, "utf8");
|
|
111975
|
+
written.push(file2.relativePath);
|
|
111976
|
+
}
|
|
111977
|
+
return { written };
|
|
111978
|
+
}
|
|
111979
|
+
|
|
111980
|
+
// ../core/dist/commands/migrate-supabase-rewrite.js
|
|
111981
|
+
var rewriteSupabaseClientInputSchema = exports_external.object({
|
|
111982
|
+
rootDir: exports_external.string().optional().describe("Project root to rewrite. Relative paths resolve against ctx.cwd. Defaults to ctx.cwd."),
|
|
111983
|
+
outputDir: exports_external.string().optional().describe("Where preview-mode writes the rewritten tree. Ignored when `apply` is true. Defaults to `<root>/migration-preview/rewritten`."),
|
|
111984
|
+
apply: exports_external.boolean().optional().describe("When true, overwrite changed files in place (originals backed up to `migration-preview/backup/` first). Default false = preview only."),
|
|
111985
|
+
pbIdentifier: exports_external.string().optional().describe("PocketBase client variable name to emit. Defaults to `pb`."),
|
|
111986
|
+
supabaseIdentifiers: exports_external.array(exports_external.string()).optional().describe("Extra Supabase client variable names to recognise (beyond `supabase`).")
|
|
111987
|
+
});
|
|
111988
|
+
async function rewriteSupabaseClient(ctx, input) {
|
|
111989
|
+
const rootAbs = input.rootDir ? resolve7(ctx.cwd, input.rootDir) : resolve7(ctx.cwd);
|
|
111990
|
+
const apply = input.apply === true;
|
|
111991
|
+
const mode = apply ? "apply" : "preview";
|
|
111992
|
+
ctx.status(`Scanning ${relative4(ctx.cwd, rootAbs) || "."} for Supabase SDK calls...`);
|
|
111993
|
+
let walk2;
|
|
111994
|
+
try {
|
|
111995
|
+
walk2 = await walkSupabaseProject({
|
|
111996
|
+
rootDir: rootAbs,
|
|
111997
|
+
pbIdentifier: input.pbIdentifier,
|
|
111998
|
+
supabaseIdentifiers: input.supabaseIdentifiers
|
|
111999
|
+
});
|
|
112000
|
+
} catch (err) {
|
|
112001
|
+
return failure2(rootAbs, mode, err, `Couldn't scan ${relative4(ctx.cwd, rootAbs) || "."}: check the path exists and is readable, then re-run.`);
|
|
112002
|
+
}
|
|
112003
|
+
const changed = walk2.files.filter((f) => f.changed);
|
|
112004
|
+
const flags = collectManualFlags(walk2);
|
|
112005
|
+
if (changed.length === 0 && flags.length === 0 && walk2.skipped.length === 0) {
|
|
112006
|
+
return {
|
|
112007
|
+
status: "ok",
|
|
112008
|
+
mode,
|
|
112009
|
+
rootDir: rootAbs,
|
|
112010
|
+
writtenTo: rootAbs,
|
|
112011
|
+
backupDir: null,
|
|
112012
|
+
filesWritten: [],
|
|
112013
|
+
changedCount: 0,
|
|
112014
|
+
flags: [],
|
|
112015
|
+
flagsByPattern: {},
|
|
112016
|
+
packageJsonChanged: false,
|
|
112017
|
+
envFilesChanged: 0,
|
|
112018
|
+
skipped: [],
|
|
112019
|
+
recovery: recoveryNone(),
|
|
112020
|
+
summary: "No Supabase SDK calls found to rewrite. If you intend to keep Supabase as your backend, " + 'set `[data] mode = "supabase"` in percher.toml instead.'
|
|
112021
|
+
};
|
|
112022
|
+
}
|
|
112023
|
+
const reportNeeded = flags.length > 0 || walk2.skipped.length > 0;
|
|
112024
|
+
const backupDir = apply && changed.length > 0 ? join18(rootAbs, "migration-preview", "backup") : null;
|
|
112025
|
+
const rewriteTarget = apply ? rootAbs : input.outputDir ? resolve7(ctx.cwd, input.outputDir) : join18(rootAbs, "migration-preview", "rewritten");
|
|
112026
|
+
const filesWritten = [];
|
|
112027
|
+
try {
|
|
112028
|
+
if (changed.length > 0) {
|
|
112029
|
+
if (apply && backupDir) {
|
|
112030
|
+
ctx.status(`Backing up ${changed.length} original file(s) to migration-preview/backup/...`);
|
|
112031
|
+
await writeWalkResult({
|
|
112032
|
+
result: { ...walk2, files: changed.map((f) => ({ ...f, rewritten: f.source })) },
|
|
112033
|
+
targetDir: backupDir,
|
|
112034
|
+
changedOnly: false
|
|
112035
|
+
});
|
|
112036
|
+
}
|
|
112037
|
+
ctx.status(apply ? `Rewriting ${changed.length} file(s) in place...` : `Writing ${changed.length} rewritten file(s) to migration-preview/rewritten/...`);
|
|
112038
|
+
const out = await writeWalkResult({
|
|
112039
|
+
result: walk2,
|
|
112040
|
+
targetDir: rewriteTarget,
|
|
112041
|
+
changedOnly: true
|
|
112042
|
+
});
|
|
112043
|
+
for (const rel of out.written) {
|
|
112044
|
+
filesWritten.push(relative4(ctx.cwd, join18(rewriteTarget, rel)));
|
|
112045
|
+
}
|
|
112046
|
+
}
|
|
112047
|
+
if (reportNeeded) {
|
|
112048
|
+
const reportAbs = join18(rootAbs, "migration-preview", "REWRITE_NOTES.md");
|
|
112049
|
+
await mkdir3(dirname5(reportAbs), { recursive: true });
|
|
112050
|
+
await writeFile3(reportAbs, renderReport({ flags, skipped: walk2.skipped }), "utf8");
|
|
112051
|
+
filesWritten.push(relative4(ctx.cwd, reportAbs));
|
|
112052
|
+
}
|
|
112053
|
+
} catch (err) {
|
|
112054
|
+
return failure2(rootAbs, mode, err, apply ? "The in-place rewrite failed partway. Your originals are safe — restore from `migration-preview/backup/` and re-run." : "Couldn't write the rewritten preview. Check the output directory is writeable and re-run.");
|
|
112055
|
+
}
|
|
112056
|
+
const flagsByPattern = {};
|
|
112057
|
+
for (const flag of flags) {
|
|
112058
|
+
flagsByPattern[flag.pattern] = (flagsByPattern[flag.pattern] ?? 0) + 1;
|
|
112059
|
+
}
|
|
112060
|
+
const recovery = reportNeeded ? recoveryAsk({ prompt: buildPrompt(flags, walk2.skipped.length), reasonCode: "unknown" }) : recoveryNone();
|
|
112061
|
+
return {
|
|
112062
|
+
status: "ok",
|
|
112063
|
+
mode,
|
|
112064
|
+
rootDir: rootAbs,
|
|
112065
|
+
writtenTo: changed.length > 0 ? rewriteTarget : rootAbs,
|
|
112066
|
+
backupDir,
|
|
112067
|
+
filesWritten,
|
|
112068
|
+
changedCount: changed.length,
|
|
112069
|
+
flags,
|
|
112070
|
+
flagsByPattern,
|
|
112071
|
+
packageJsonChanged: walk2.summary.packageJsonChanged,
|
|
112072
|
+
envFilesChanged: walk2.summary.envFilesChanged,
|
|
112073
|
+
skipped: walk2.skipped,
|
|
112074
|
+
recovery,
|
|
112075
|
+
summary: renderSummary2({ mode, changed: changed.length, walk: walk2, flagCount: flags.length })
|
|
112076
|
+
};
|
|
112077
|
+
}
|
|
112078
|
+
function collectManualFlags(walk2) {
|
|
112079
|
+
const out = [];
|
|
112080
|
+
for (const file2 of walk2.files) {
|
|
112081
|
+
for (const flag of file2.flags) {
|
|
112082
|
+
if (flag.kind === "manual_review" || flag.kind === "unsupported") {
|
|
112083
|
+
out.push({
|
|
112084
|
+
file: file2.relativePath,
|
|
112085
|
+
line: flag.line,
|
|
112086
|
+
column: flag.column,
|
|
112087
|
+
kind: flag.kind,
|
|
112088
|
+
pattern: flag.pattern,
|
|
112089
|
+
note: flag.note
|
|
112090
|
+
});
|
|
112091
|
+
}
|
|
112092
|
+
}
|
|
112093
|
+
}
|
|
112094
|
+
return out;
|
|
112095
|
+
}
|
|
112096
|
+
function buildPrompt(flags, skippedCount) {
|
|
112097
|
+
const rewritten = flags.filter((f) => f.kind === "manual_review").length;
|
|
112098
|
+
const untouched = flags.filter((f) => f.kind === "unsupported").length;
|
|
112099
|
+
const bits = [];
|
|
112100
|
+
if (rewritten > 0) {
|
|
112101
|
+
bits.push(`${rewritten} rewritten to PocketBase but with semantics that differ from Supabase`);
|
|
112102
|
+
}
|
|
112103
|
+
if (untouched > 0) {
|
|
112104
|
+
bits.push(`${untouched} left untouched (no PocketBase equivalent — storage, realtime, rpc, or edge functions)`);
|
|
112105
|
+
}
|
|
112106
|
+
if (skippedCount > 0) {
|
|
112107
|
+
bits.push(`${skippedCount} file${skippedCount === 1 ? "" : "s"} couldn't be parsed`);
|
|
112108
|
+
}
|
|
112109
|
+
return `Some locations need review: ${bits.join("; ")}. Each is listed with its file and line in migration-preview/REWRITE_NOTES.md — check them before deploying.`;
|
|
112110
|
+
}
|
|
112111
|
+
function renderSummary2(args) {
|
|
112112
|
+
const parts = [];
|
|
112113
|
+
if (args.changed > 0) {
|
|
112114
|
+
const where = args.mode === "apply" ? "rewritten in place (originals in `migration-preview/backup/`)" : "written to `migration-preview/rewritten/` for review";
|
|
112115
|
+
parts.push(`${args.changed} file${args.changed === 1 ? "" : "s"} ${where}.`);
|
|
112116
|
+
} else {
|
|
112117
|
+
parts.push("No files needed automatic rewriting.");
|
|
112118
|
+
}
|
|
112119
|
+
if (args.walk.summary.packageJsonChanged) {
|
|
112120
|
+
parts.push("`package.json` swapped `@supabase/supabase-js` → `pocketbase`.");
|
|
112121
|
+
}
|
|
112122
|
+
if (args.walk.summary.envFilesChanged > 0) {
|
|
112123
|
+
parts.push(`${args.walk.summary.envFilesChanged} .env file${args.walk.summary.envFilesChanged === 1 ? "" : "s"} stubbed with PocketBase keys.`);
|
|
112124
|
+
}
|
|
112125
|
+
if (args.flagCount > 0) {
|
|
112126
|
+
parts.push(`${args.flagCount} pattern${args.flagCount === 1 ? "" : "s"} need manual review — see \`migration-preview/REWRITE_NOTES.md\`.`);
|
|
112127
|
+
}
|
|
112128
|
+
if (args.walk.skipped.length > 0) {
|
|
112129
|
+
parts.push(`${args.walk.skipped.length} file${args.walk.skipped.length === 1 ? "" : "s"} couldn't be parsed (listed in \`REWRITE_NOTES.md\`).`);
|
|
112130
|
+
}
|
|
112131
|
+
return parts.join(" ");
|
|
112132
|
+
}
|
|
112133
|
+
function renderReport(args) {
|
|
112134
|
+
const lines = [];
|
|
112135
|
+
lines.push("# Supabase → PocketBase — review notes");
|
|
112136
|
+
lines.push("");
|
|
112137
|
+
lines.push("The automated rewrite handled auth and CRUD. The locations below still need a human: some were rewritten but their semantics differ from Supabase, others have no PocketBase equivalent and were left untouched. There are no inline markers — work from this list.");
|
|
112138
|
+
lines.push("");
|
|
112139
|
+
const rewritten = args.flags.filter((f) => f.kind === "manual_review");
|
|
112140
|
+
const untouched = args.flags.filter((f) => f.kind === "unsupported");
|
|
112141
|
+
if (rewritten.length > 0) {
|
|
112142
|
+
lines.push("## Rewritten — verify the semantics");
|
|
112143
|
+
lines.push("");
|
|
112144
|
+
lines.push("These calls were converted to PocketBase, but the behaviour isn't identical (event shapes, filter escaping, pagination). Confirm each still does what you intend.");
|
|
112145
|
+
lines.push("");
|
|
112146
|
+
appendFlagsByFile(lines, rewritten);
|
|
112147
|
+
}
|
|
112148
|
+
if (untouched.length > 0) {
|
|
112149
|
+
lines.push("## Left untouched — rewrite by hand");
|
|
112150
|
+
lines.push("");
|
|
112151
|
+
lines.push("These have no clean PocketBase equivalent, so they remain as Supabase calls in your source. Replace each one yourself.");
|
|
112152
|
+
lines.push("");
|
|
112153
|
+
appendFlagsByFile(lines, untouched);
|
|
112154
|
+
}
|
|
112155
|
+
if (args.skipped.length > 0) {
|
|
112156
|
+
lines.push("## Files that couldn't be parsed");
|
|
112157
|
+
lines.push("");
|
|
112158
|
+
lines.push("These were skipped — review them manually for Supabase calls the rewriter missed.");
|
|
112159
|
+
lines.push("");
|
|
112160
|
+
for (const file2 of args.skipped) {
|
|
112161
|
+
lines.push(`- \`${file2.relativePath}\` — ${file2.reason}${file2.detail ? `: ${file2.detail}` : ""}`);
|
|
112162
|
+
}
|
|
112163
|
+
lines.push("");
|
|
112164
|
+
}
|
|
112165
|
+
return lines.join(`
|
|
112166
|
+
`);
|
|
112167
|
+
}
|
|
112168
|
+
function appendFlagsByFile(lines, flags) {
|
|
112169
|
+
const byFile = new Map;
|
|
112170
|
+
for (const flag of flags) {
|
|
112171
|
+
const list = byFile.get(flag.file) ?? [];
|
|
112172
|
+
list.push(flag);
|
|
112173
|
+
byFile.set(flag.file, list);
|
|
112174
|
+
}
|
|
112175
|
+
for (const [file2, fileFlags] of byFile) {
|
|
112176
|
+
lines.push(`### \`${file2}\``);
|
|
112177
|
+
lines.push("");
|
|
112178
|
+
for (const flag of fileFlags) {
|
|
112179
|
+
const loc = flag.line !== undefined ? `L${flag.line}${flag.column !== undefined ? `:${flag.column}` : ""}` : "(location unknown)";
|
|
112180
|
+
lines.push(`- ${loc} \`${flag.pattern}\` — ${flag.note}`);
|
|
112181
|
+
}
|
|
112182
|
+
lines.push("");
|
|
112183
|
+
}
|
|
112184
|
+
}
|
|
112185
|
+
function failure2(rootAbs, mode, err, suggestion) {
|
|
112186
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
112187
|
+
return {
|
|
112188
|
+
status: "failed",
|
|
112189
|
+
mode,
|
|
112190
|
+
rootDir: rootAbs,
|
|
112191
|
+
writtenTo: rootAbs,
|
|
112192
|
+
backupDir: null,
|
|
112193
|
+
filesWritten: [],
|
|
112194
|
+
changedCount: 0,
|
|
112195
|
+
flags: [],
|
|
112196
|
+
flagsByPattern: {},
|
|
112197
|
+
packageJsonChanged: false,
|
|
112198
|
+
envFilesChanged: 0,
|
|
112199
|
+
skipped: [],
|
|
112200
|
+
recovery: recoveryAsk({
|
|
112201
|
+
prompt: `${suggestion} (${message})`,
|
|
112202
|
+
reasonCode: "unknown",
|
|
112203
|
+
retryable: true
|
|
112204
|
+
}),
|
|
112205
|
+
summary: `Client rewrite failed: ${message}`,
|
|
112206
|
+
error: {
|
|
112207
|
+
code: "rewrite_failed",
|
|
112208
|
+
title: "Supabase client rewrite failed",
|
|
112209
|
+
explanation: message,
|
|
112210
|
+
suggestion
|
|
112211
|
+
}
|
|
112212
|
+
};
|
|
112213
|
+
}
|
|
110413
112214
|
// ../core/dist/commands/migrate-supabase-schema.js
|
|
110414
|
-
import { mkdir as
|
|
110415
|
-
import { isAbsolute as
|
|
112215
|
+
import { mkdir as mkdir4, writeFile as writeFile4 } from "node:fs/promises";
|
|
112216
|
+
import { isAbsolute as isAbsolute3, join as join19, relative as relative5, resolve as resolve8 } from "node:path";
|
|
110416
112217
|
|
|
110417
112218
|
// ../core/dist/commands/migrate-supabase-scripts.js
|
|
110418
112219
|
function generateDataImportScripts(preview) {
|
|
@@ -110860,7 +112661,7 @@ var migrateSupabaseSchemaInputSchema = exports_external.object({
|
|
|
110860
112661
|
});
|
|
110861
112662
|
async function migrateSupabaseSchema(ctx, input) {
|
|
110862
112663
|
const outputDirAbs = resolveOutputDir(ctx.cwd, input.outputDir);
|
|
110863
|
-
const outputDirRel =
|
|
112664
|
+
const outputDirRel = relative5(ctx.cwd, outputDirAbs) || ".";
|
|
110864
112665
|
ctx.status(`Inspecting Supabase project ${input.projectRef}...`);
|
|
110865
112666
|
const inspection = await inspectSupabase(ctx, {
|
|
110866
112667
|
projectRef: input.projectRef,
|
|
@@ -110906,7 +112707,7 @@ async function migrateSupabaseSchema(ctx, input) {
|
|
|
110906
112707
|
}
|
|
110907
112708
|
};
|
|
110908
112709
|
}
|
|
110909
|
-
const summary =
|
|
112710
|
+
const summary = renderSummary3({
|
|
110910
112711
|
projectRef: input.projectRef,
|
|
110911
112712
|
outputDirRel,
|
|
110912
112713
|
inspection,
|
|
@@ -110924,28 +112725,28 @@ async function migrateSupabaseSchema(ctx, input) {
|
|
|
110924
112725
|
}
|
|
110925
112726
|
function resolveOutputDir(cwd, requested) {
|
|
110926
112727
|
const raw = requested ?? "./migration-preview";
|
|
110927
|
-
return
|
|
112728
|
+
return isAbsolute3(raw) ? raw : resolve8(cwd, raw);
|
|
110928
112729
|
}
|
|
110929
112730
|
async function writePreviewFiles(ctx, outputDir, preview) {
|
|
110930
|
-
await
|
|
112731
|
+
await mkdir4(outputDir, { recursive: true });
|
|
110931
112732
|
const schemaJson = renderSchemaJson(preview);
|
|
110932
112733
|
const notesMd = renderMigrationNotes(preview);
|
|
110933
112734
|
const scripts = generateDataImportScripts(preview);
|
|
110934
|
-
const schemaPath =
|
|
110935
|
-
const notesPath =
|
|
110936
|
-
const migratePath =
|
|
110937
|
-
const storagePath =
|
|
110938
|
-
await
|
|
110939
|
-
await
|
|
110940
|
-
await
|
|
112735
|
+
const schemaPath = join19(outputDir, "pb_schema.json");
|
|
112736
|
+
const notesPath = join19(outputDir, "MIGRATION_NOTES.md");
|
|
112737
|
+
const migratePath = join19(outputDir, "pb_migrate.js");
|
|
112738
|
+
const storagePath = join19(outputDir, "pb_migrate_storage.js");
|
|
112739
|
+
await writeFile4(schemaPath, schemaJson, "utf8");
|
|
112740
|
+
await writeFile4(notesPath, notesMd, "utf8");
|
|
112741
|
+
await writeFile4(migratePath, scripts.pbMigrate, "utf8");
|
|
110941
112742
|
const written = [
|
|
110942
|
-
|
|
110943
|
-
|
|
110944
|
-
|
|
112743
|
+
relative5(ctx.cwd, schemaPath),
|
|
112744
|
+
relative5(ctx.cwd, notesPath),
|
|
112745
|
+
relative5(ctx.cwd, migratePath)
|
|
110945
112746
|
];
|
|
110946
112747
|
if (scripts.pbMigrateStorage !== null) {
|
|
110947
|
-
await
|
|
110948
|
-
written.push(
|
|
112748
|
+
await writeFile4(storagePath, scripts.pbMigrateStorage, "utf8");
|
|
112749
|
+
written.push(relative5(ctx.cwd, storagePath));
|
|
110949
112750
|
}
|
|
110950
112751
|
return written;
|
|
110951
112752
|
}
|
|
@@ -111094,7 +112895,7 @@ function renderMigrationNotes(preview) {
|
|
|
111094
112895
|
return lines.join(`
|
|
111095
112896
|
`);
|
|
111096
112897
|
}
|
|
111097
|
-
function
|
|
112898
|
+
function renderSummary3(args) {
|
|
111098
112899
|
const counts = args.preview.summary;
|
|
111099
112900
|
return [
|
|
111100
112901
|
`Wrote migration preview for Supabase project ${args.projectRef} to ${args.outputDirRel}/.`,
|
|
@@ -111104,29 +112905,6 @@ function renderSummary2(args) {
|
|
|
111104
112905
|
"Review `MIGRATION_NOTES.md` before running the import step."
|
|
111105
112906
|
].join(" ");
|
|
111106
112907
|
}
|
|
111107
|
-
// ../core/dist/commands/migrate-supabase-sdk.js
|
|
111108
|
-
var import_jscodeshift = __toESM(require_core3(), 1);
|
|
111109
|
-
var tsx = import_jscodeshift.default.withParser("tsx");
|
|
111110
|
-
var STORAGE_OPERATIONS = new Set([
|
|
111111
|
-
"upload",
|
|
111112
|
-
"uploadToSignedUrl",
|
|
111113
|
-
"download",
|
|
111114
|
-
"list",
|
|
111115
|
-
"remove",
|
|
111116
|
-
"move",
|
|
111117
|
-
"copy",
|
|
111118
|
-
"createSignedUrl",
|
|
111119
|
-
"createSignedUrls",
|
|
111120
|
-
"createSignedUploadUrl",
|
|
111121
|
-
"getPublicUrl",
|
|
111122
|
-
"update",
|
|
111123
|
-
"exists",
|
|
111124
|
-
"info"
|
|
111125
|
-
]);
|
|
111126
|
-
var CHAIN_CONTINUATIONS = new Set(["then", "catch", "finally"]);
|
|
111127
|
-
// ../core/dist/commands/migrate-supabase-walker.js
|
|
111128
|
-
var import_ignore3 = __toESM(require_ignore(), 1);
|
|
111129
|
-
var REWRITABLE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
111130
112908
|
// ../core/dist/commands/open.js
|
|
111131
112909
|
var openInputSchema = exports_external.object({
|
|
111132
112910
|
app: exports_external.string().optional()
|
|
@@ -111184,7 +112962,7 @@ async function previewBranchShow(ctx, input = {}) {
|
|
|
111184
112962
|
}
|
|
111185
112963
|
// ../core/dist/commands/publish.js
|
|
111186
112964
|
import { existsSync as existsSync14 } from "node:fs";
|
|
111187
|
-
import { join as
|
|
112965
|
+
import { join as join22 } from "node:path";
|
|
111188
112966
|
|
|
111189
112967
|
// ../shared/dist/pow.js
|
|
111190
112968
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -111561,7 +113339,7 @@ async function runDeployWithRetry(opts) {
|
|
|
111561
113339
|
|
|
111562
113340
|
// ../core/dist/commands/env-scan.js
|
|
111563
113341
|
import { readdirSync as readdirSync3, readFileSync as readFileSync10, statSync as statSync3 } from "node:fs";
|
|
111564
|
-
import { join as
|
|
113342
|
+
import { join as join20 } from "node:path";
|
|
111565
113343
|
var SOURCE_EXTS = new Set([
|
|
111566
113344
|
".ts",
|
|
111567
113345
|
".tsx",
|
|
@@ -111598,7 +113376,7 @@ function scanForMissingBuildEnvRefs(cwd, existingKeys) {
|
|
|
111598
113376
|
continue;
|
|
111599
113377
|
let content;
|
|
111600
113378
|
try {
|
|
111601
|
-
content = readFileSync10(
|
|
113379
|
+
content = readFileSync10(join20(cwd, rel), "utf8");
|
|
111602
113380
|
} catch {
|
|
111603
113381
|
continue;
|
|
111604
113382
|
}
|
|
@@ -111630,7 +113408,7 @@ function* walkDir(dir, base) {
|
|
|
111630
113408
|
for (const name of entries) {
|
|
111631
113409
|
if (SKIP_DIRS.has(name))
|
|
111632
113410
|
continue;
|
|
111633
|
-
const full =
|
|
113411
|
+
const full = join20(dir, name);
|
|
111634
113412
|
let st;
|
|
111635
113413
|
try {
|
|
111636
113414
|
st = statSync3(full);
|
|
@@ -111991,9 +113769,9 @@ function titleFromCode(code) {
|
|
|
111991
113769
|
|
|
111992
113770
|
// ../core/dist/commands/publish-node.js
|
|
111993
113771
|
import { existsSync as existsSync13, readFileSync as readFileSync11 } from "node:fs";
|
|
111994
|
-
import { join as
|
|
113772
|
+
import { join as join21 } from "node:path";
|
|
111995
113773
|
function resolveNodeVersion(cwd) {
|
|
111996
|
-
const nvmrc =
|
|
113774
|
+
const nvmrc = join21(cwd, ".nvmrc");
|
|
111997
113775
|
if (existsSync13(nvmrc)) {
|
|
111998
113776
|
try {
|
|
111999
113777
|
const v = readFileSync11(nvmrc, "utf8").trim();
|
|
@@ -112001,7 +113779,7 @@ function resolveNodeVersion(cwd) {
|
|
|
112001
113779
|
return { value: v, source: ".nvmrc" };
|
|
112002
113780
|
} catch {}
|
|
112003
113781
|
}
|
|
112004
|
-
const pkgPath =
|
|
113782
|
+
const pkgPath = join21(cwd, "package.json");
|
|
112005
113783
|
if (!existsSync13(pkgPath))
|
|
112006
113784
|
return null;
|
|
112007
113785
|
try {
|
|
@@ -112027,7 +113805,7 @@ var publishInputSchema = exports_external.object({
|
|
|
112027
113805
|
var SUSPICIOUS_BYTES = 50 * 1024 * 1024;
|
|
112028
113806
|
var SUSPICIOUS_FILES = 1e4;
|
|
112029
113807
|
function tomlPathFor2(cwd) {
|
|
112030
|
-
return
|
|
113808
|
+
return join22(cwd, "percher.toml");
|
|
112031
113809
|
}
|
|
112032
113810
|
async function buildReplacedResult2(opts) {
|
|
112033
113811
|
const { ctx, app, deployment, tarball, cwd } = opts;
|
|
@@ -112647,13 +114425,11 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
112647
114425
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
112648
114426
|
};
|
|
112649
114427
|
}
|
|
112650
|
-
saveConfig({
|
|
112651
|
-
|
|
112652
|
-
|
|
112653
|
-
|
|
112654
|
-
|
|
112655
|
-
expiresAt: created.expiresAt
|
|
112656
|
-
}
|
|
114428
|
+
saveConfig({ token: created.token });
|
|
114429
|
+
setAnonClaim({
|
|
114430
|
+
app: created.app.name,
|
|
114431
|
+
claimToken: created.claimToken,
|
|
114432
|
+
expiresAt: created.expiresAt
|
|
112657
114433
|
});
|
|
112658
114434
|
const newClient = new PercherClient({
|
|
112659
114435
|
apiUrl: ctx.client.apiUrl,
|
|
@@ -112694,7 +114470,7 @@ async function handleAnonymousPublish(ctx, config2, input, tarball) {
|
|
|
112694
114470
|
};
|
|
112695
114471
|
}
|
|
112696
114472
|
async function loadOrGenerate(ctx) {
|
|
112697
|
-
const tomlPath =
|
|
114473
|
+
const tomlPath = join22(ctx.cwd, "percher.toml");
|
|
112698
114474
|
if (!existsSync14(tomlPath)) {
|
|
112699
114475
|
ctx.status("No percher.toml found — detecting framework...");
|
|
112700
114476
|
await init(ctx);
|
|
@@ -112745,7 +114521,7 @@ function emitPreflight(ctx, config2, tarball) {
|
|
|
112745
114521
|
}
|
|
112746
114522
|
// ../core/dist/commands/push.js
|
|
112747
114523
|
import { existsSync as existsSync15 } from "node:fs";
|
|
112748
|
-
import { join as
|
|
114524
|
+
import { join as join23 } from "node:path";
|
|
112749
114525
|
var pushInputSchema = exports_external.object({
|
|
112750
114526
|
dryRun: exports_external.boolean().optional(),
|
|
112751
114527
|
force: exports_external.boolean().optional(),
|
|
@@ -112756,7 +114532,7 @@ var SUSPICIOUS_BYTES2 = 50 * 1024 * 1024;
|
|
|
112756
114532
|
var SUSPICIOUS_FILES2 = 1e4;
|
|
112757
114533
|
var PLACEHOLDER_PREFIXES = ["add-your-", "your-key-here"];
|
|
112758
114534
|
async function loadOrGenerate2(ctx) {
|
|
112759
|
-
const tomlPath =
|
|
114535
|
+
const tomlPath = join23(ctx.cwd, "percher.toml");
|
|
112760
114536
|
if (!existsSync15(tomlPath)) {
|
|
112761
114537
|
ctx.status("No percher.toml found — detecting framework...");
|
|
112762
114538
|
const result = await init(ctx);
|
|
@@ -112868,7 +114644,7 @@ async function push(ctx, input = {}, internals = {}) {
|
|
|
112868
114644
|
fileCount: tarball.fileCount,
|
|
112869
114645
|
recovery: RECOVERY_NONE,
|
|
112870
114646
|
summary: `Dry run for ${config2.app.name}: ${tarball.fileCount} files, ${(tarball.bytes / 1024).toFixed(1)} KB — no deploy performed.`,
|
|
112871
|
-
configPath:
|
|
114647
|
+
configPath: join23(ctx.cwd, "percher.toml"),
|
|
112872
114648
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
112873
114649
|
};
|
|
112874
114650
|
}
|
|
@@ -113051,7 +114827,7 @@ ${deployment.errorMessage}` : "";
|
|
|
113051
114827
|
fileCount: tarball.fileCount,
|
|
113052
114828
|
recovery: RECOVERY_NONE,
|
|
113053
114829
|
summary,
|
|
113054
|
-
configPath:
|
|
114830
|
+
configPath: join23(ctx.cwd, "percher.toml"),
|
|
113055
114831
|
bundle: { fileCount: tarball.fileCount, bytes: tarball.bytes }
|
|
113056
114832
|
};
|
|
113057
114833
|
}
|
|
@@ -113381,7 +115157,7 @@ function failureResult(error48) {
|
|
|
113381
115157
|
}
|
|
113382
115158
|
// ../core/dist/commands/rename.js
|
|
113383
115159
|
import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
|
|
113384
|
-
import { join as
|
|
115160
|
+
import { join as join24 } from "node:path";
|
|
113385
115161
|
var renameInputSchema = exports_external.object({
|
|
113386
115162
|
app: exports_external.string().optional(),
|
|
113387
115163
|
name: exports_external.string().min(3).max(40)
|
|
@@ -113401,7 +115177,7 @@ async function rename2(ctx, input) {
|
|
|
113401
115177
|
};
|
|
113402
115178
|
}
|
|
113403
115179
|
function updateLocalTomlName(cwd, oldName, newName) {
|
|
113404
|
-
const p =
|
|
115180
|
+
const p = join24(cwd, "percher.toml");
|
|
113405
115181
|
if (!existsSync16(p))
|
|
113406
115182
|
return false;
|
|
113407
115183
|
try {
|
|
@@ -113418,18 +115194,18 @@ function updateLocalTomlName(cwd, oldName, newName) {
|
|
|
113418
115194
|
}
|
|
113419
115195
|
}
|
|
113420
115196
|
// ../core/dist/commands/reproduce.js
|
|
113421
|
-
import { spawn } from "node:child_process";
|
|
113422
115197
|
import { mkdtempSync, writeFileSync as writeFileSync9 } from "node:fs";
|
|
113423
115198
|
import { tmpdir } from "node:os";
|
|
113424
|
-
import { join as
|
|
115199
|
+
import { join as join25 } from "node:path";
|
|
115200
|
+
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
113425
115201
|
function runProcessExit(cmd, args, opts = {}) {
|
|
113426
|
-
return new Promise((
|
|
113427
|
-
const child =
|
|
115202
|
+
return new Promise((resolve9, reject) => {
|
|
115203
|
+
const child = import_cross_spawn.default(cmd, args, {
|
|
113428
115204
|
cwd: opts.cwd,
|
|
113429
115205
|
stdio: opts.inherit ? "inherit" : "ignore"
|
|
113430
115206
|
});
|
|
113431
115207
|
child.on("error", reject);
|
|
113432
|
-
child.on("close", (code) =>
|
|
115208
|
+
child.on("close", (code) => resolve9(code ?? 1));
|
|
113433
115209
|
});
|
|
113434
115210
|
}
|
|
113435
115211
|
var reproduceInputSchema = exports_external.object({
|
|
@@ -113515,8 +115291,8 @@ async function reproduce(ctx, input) {
|
|
|
113515
115291
|
const envMap = await ctx.client.env.list(app.id);
|
|
113516
115292
|
currentAppEnvKeys = Object.keys(envMap).sort();
|
|
113517
115293
|
} catch {}
|
|
113518
|
-
const tmpDir = mkdtempSync(
|
|
113519
|
-
const tarballPath =
|
|
115294
|
+
const tmpDir = mkdtempSync(join25(tmpdir(), `percher-reproduce-${input.deployId}-`));
|
|
115295
|
+
const tarballPath = join25(tmpDir, "source.tar.gz");
|
|
113520
115296
|
writeFileSync9(tarballPath, bytes);
|
|
113521
115297
|
let extracted = false;
|
|
113522
115298
|
try {
|
|
@@ -114856,8 +116632,8 @@ function registerAppsCommands(cli, ctx) {
|
|
|
114856
116632
|
deployId,
|
|
114857
116633
|
timeoutSeconds: Math.min(Math.ceil(remainingMs / 1000), 30)
|
|
114858
116634
|
}, { signal: callController.signal }),
|
|
114859
|
-
new Promise((
|
|
114860
|
-
raceTimer = setTimeout(() =>
|
|
116635
|
+
new Promise((resolve9) => {
|
|
116636
|
+
raceTimer = setTimeout(() => resolve9(null), remainingMs);
|
|
114861
116637
|
})
|
|
114862
116638
|
]);
|
|
114863
116639
|
} finally {
|
|
@@ -115323,8 +117099,8 @@ function registerDeploysCommands(cli, ctx, argv) {
|
|
|
115323
117099
|
const { summary, files } = result;
|
|
115324
117100
|
await writeLine(ctx, `${summary.filesChanged} file${summary.filesChanged === 1 ? "" : "s"} changed · ${import_picocolors7.default.green(`+${summary.additions}`)} ${import_picocolors7.default.red(`−${summary.deletions}`)} (${result.base.slice(0, 10)} → ${result.head.slice(0, 10)})`);
|
|
115325
117101
|
for (const f of files) {
|
|
115326
|
-
const
|
|
115327
|
-
await writeLine(ctx, ` ${f.status} ${f.path} ${
|
|
117102
|
+
const stat2 = f.binary ? import_picocolors7.default.dim("binary") : `${import_picocolors7.default.green(`+${f.additions}`)} ${import_picocolors7.default.red(`−${f.deletions}`)}`;
|
|
117103
|
+
await writeLine(ctx, ` ${f.status} ${f.path} ${stat2}${f.truncated ? import_picocolors7.default.dim(" (truncated)") : ""}`);
|
|
115328
117104
|
if (options.patch && f.patch) {
|
|
115329
117105
|
await writeLine(ctx, f.patch.replace(/\n$/, ""));
|
|
115330
117106
|
}
|
|
@@ -115396,7 +117172,7 @@ function registerEnvCommands(cli, ctx) {
|
|
|
115396
117172
|
if (action === "set") {
|
|
115397
117173
|
const { resolveEnvSetInputs: resolveEnvSetInputs2, EnvSetInputError: EnvSetInputError2 } = await Promise.resolve().then(() => (init_env_set_input(), exports_env_set_input));
|
|
115398
117174
|
const { promptHidden: promptHidden2 } = await Promise.resolve().then(() => (init_prompt_hidden(), exports_prompt_hidden));
|
|
115399
|
-
const { readFile:
|
|
117175
|
+
const { readFile: readFile4 } = await import("node:fs/promises");
|
|
115400
117176
|
try {
|
|
115401
117177
|
const values = await resolveEnvSetInputs2({
|
|
115402
117178
|
args,
|
|
@@ -115408,7 +117184,7 @@ function registerEnvCommands(cli, ctx) {
|
|
|
115408
117184
|
chunks.push(c);
|
|
115409
117185
|
return Buffer.concat(chunks).toString("utf8");
|
|
115410
117186
|
},
|
|
115411
|
-
readFile: async (p) =>
|
|
117187
|
+
readFile: async (p) => readFile4(p, "utf8"),
|
|
115412
117188
|
promptHidden: promptHidden2
|
|
115413
117189
|
});
|
|
115414
117190
|
await envSet(ctx, { app: options.app, values });
|
|
@@ -115522,9 +117298,13 @@ function registerGithubCommands(cli, ctx) {
|
|
|
115522
117298
|
// src/commands/migrate.ts
|
|
115523
117299
|
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
115524
117300
|
function registerMigrateCommands(cli, ctx) {
|
|
115525
|
-
cli.command("migrate-from-supabase", "Migrate a Supabase project to PocketBase
|
|
117301
|
+
cli.command("migrate-from-supabase", "Migrate a Supabase project to PocketBase: schema + data-import script, optionally rewrite SDK calls").option("--project <ref>", "Supabase project reference (the 20-char id from the project URL)").option("--token <token>", "Supabase personal access token (sbp_...). Read from SUPABASE_ACCESS_TOKEN if omitted.").option("--inspect-only", "Only print the schema that would migrate — read-only, no file writes").option("--output-dir <dir>", "Where to write the preview files (default: ./migration-preview/)").option("--rewrite-client", "Also convert your Supabase SDK calls to PocketBase across the project").option("--apply", "With --rewrite-client: overwrite files in place (originals backed up first). Default: preview only.").option("--root <dir>", "Project root to rewrite with --rewrite-client (default: current directory)").option("--json", "Output the structured result as JSON").action(async (options) => {
|
|
115526
117302
|
const projectRef = options.project;
|
|
115527
117303
|
const token = options.token ?? ctx.env.SUPABASE_ACCESS_TOKEN;
|
|
117304
|
+
if (options.apply && !options.rewriteClient) {
|
|
117305
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} --apply only applies to the client rewrite. Pass --rewrite-client --apply together.`);
|
|
117306
|
+
throw new SilentExitError(1);
|
|
117307
|
+
}
|
|
115528
117308
|
if (!projectRef) {
|
|
115529
117309
|
await writeLine(ctx, `${import_picocolors11.default.red("✗")} Missing --project. Pass your Supabase project ref (e.g. --project abcdefghijklmnopqrst).`);
|
|
115530
117310
|
throw new SilentExitError(1);
|
|
@@ -115551,15 +117331,28 @@ function registerMigrateCommands(cli, ctx) {
|
|
|
115551
117331
|
token,
|
|
115552
117332
|
outputDir: options.outputDir
|
|
115553
117333
|
});
|
|
117334
|
+
let rewrite;
|
|
117335
|
+
if (options.rewriteClient && result.status === "ok") {
|
|
117336
|
+
rewrite = await rewriteSupabaseClient(ctx, {
|
|
117337
|
+
rootDir: options.root,
|
|
117338
|
+
apply: options.apply === true
|
|
117339
|
+
});
|
|
117340
|
+
}
|
|
115554
117341
|
if (options.json) {
|
|
115555
|
-
await writeLine(ctx, JSON.stringify(result, null, 2));
|
|
115556
|
-
if (result.status === "failed")
|
|
117342
|
+
await writeLine(ctx, JSON.stringify(rewrite ? { schema: result, rewrite } : result, null, 2));
|
|
117343
|
+
if (result.status === "failed" || rewrite?.status === "failed") {
|
|
115557
117344
|
throw new SilentExitError(1);
|
|
117345
|
+
}
|
|
115558
117346
|
return;
|
|
115559
117347
|
}
|
|
115560
|
-
await renderSchemaHuman(ctx, result
|
|
115561
|
-
|
|
117348
|
+
await renderSchemaHuman(ctx, result, {
|
|
117349
|
+
clientRewriteRequested: options.rewriteClient === true
|
|
117350
|
+
});
|
|
117351
|
+
if (rewrite)
|
|
117352
|
+
await renderRewriteHuman(ctx, rewrite);
|
|
117353
|
+
if (result.status === "failed" || rewrite?.status === "failed") {
|
|
115562
117354
|
throw new SilentExitError(1);
|
|
117355
|
+
}
|
|
115563
117356
|
});
|
|
115564
117357
|
}
|
|
115565
117358
|
async function renderInspectHuman(ctx, result) {
|
|
@@ -115605,9 +117398,9 @@ async function renderInspectHuman(ctx, result) {
|
|
|
115605
117398
|
}
|
|
115606
117399
|
}
|
|
115607
117400
|
await writeLine(ctx, "");
|
|
115608
|
-
await writeLine(ctx, import_picocolors11.default.dim("--inspect-only is read-only. Drop the flag to also write the
|
|
117401
|
+
await writeLine(ctx, import_picocolors11.default.dim("--inspect-only is read-only. Drop the flag to also write the PocketBase schema preview + pb_migrate.js data-import script to ./migration-preview/."));
|
|
115609
117402
|
}
|
|
115610
|
-
async function renderSchemaHuman(ctx, result) {
|
|
117403
|
+
async function renderSchemaHuman(ctx, result, opts) {
|
|
115611
117404
|
if (result.status === "failed") {
|
|
115612
117405
|
const err = result.error;
|
|
115613
117406
|
await writeLine(ctx, `${import_picocolors11.default.red("✗")} ${err?.title ?? "Migration preview failed"}`);
|
|
@@ -115646,7 +117439,55 @@ async function renderSchemaHuman(ctx, result) {
|
|
|
115646
117439
|
}
|
|
115647
117440
|
}
|
|
115648
117441
|
await writeLine(ctx, "");
|
|
115649
|
-
await writeLine(ctx, import_picocolors11.default.dim("
|
|
117442
|
+
await writeLine(ctx, import_picocolors11.default.dim("Preview only — nothing has touched your PocketBase yet. ./migration-preview/ includes pb_migrate.js, the data-import script: review MIGRATION_NOTES.md, then run it against your app's PocketBase to copy your rows over."));
|
|
117443
|
+
if (!opts.clientRewriteRequested) {
|
|
117444
|
+
await writeLine(ctx, import_picocolors11.default.dim("Add --rewrite-client to also convert your Supabase SDK calls to PocketBase (preview first; --apply writes in place)."));
|
|
117445
|
+
}
|
|
117446
|
+
}
|
|
117447
|
+
async function renderRewriteHuman(ctx, result) {
|
|
117448
|
+
await writeLine(ctx, "");
|
|
117449
|
+
if (result.status === "failed") {
|
|
117450
|
+
const err = result.error;
|
|
117451
|
+
await writeLine(ctx, `${import_picocolors11.default.red("✗")} ${err?.title ?? "Client rewrite failed"}`);
|
|
117452
|
+
if (err?.explanation)
|
|
117453
|
+
await writeLine(ctx, ` ${err.explanation}`);
|
|
117454
|
+
if (err?.suggestion)
|
|
117455
|
+
await writeLine(ctx, import_picocolors11.default.dim(` ${err.suggestion}`));
|
|
117456
|
+
return;
|
|
117457
|
+
}
|
|
117458
|
+
await writeLine(ctx, `${import_picocolors11.default.green("✓")} ${result.summary}`);
|
|
117459
|
+
if (result.filesWritten.length > 0) {
|
|
117460
|
+
await writeLine(ctx, "");
|
|
117461
|
+
await writeLine(ctx, import_picocolors11.default.bold("Files written"));
|
|
117462
|
+
for (const path of result.filesWritten.slice(0, 20)) {
|
|
117463
|
+
await writeLine(ctx, ` ${import_picocolors11.default.cyan(path)}`);
|
|
117464
|
+
}
|
|
117465
|
+
if (result.filesWritten.length > 20) {
|
|
117466
|
+
await writeLine(ctx, import_picocolors11.default.dim(` …and ${result.filesWritten.length - 20} more`));
|
|
117467
|
+
}
|
|
117468
|
+
}
|
|
117469
|
+
if (result.flags.length > 0) {
|
|
117470
|
+
await writeLine(ctx, "");
|
|
117471
|
+
await writeLine(ctx, import_picocolors11.default.bold("Needs review (see migration-preview/REWRITE_NOTES.md)"));
|
|
117472
|
+
for (const flag of result.flags.slice(0, 15)) {
|
|
117473
|
+
const loc = flag.line !== undefined ? `:${flag.line}` : "";
|
|
117474
|
+
const tag = flag.kind === "manual_review" ? "rewritten, verify semantics" : "left untouched";
|
|
117475
|
+
await writeLine(ctx, ` ${import_picocolors11.default.yellow("⚠")} ${import_picocolors11.default.cyan(`${flag.file}${loc}`)} ${flag.pattern} ${import_picocolors11.default.dim(`(${tag}) — ${flag.note}`)}`);
|
|
117476
|
+
}
|
|
117477
|
+
if (result.flags.length > 15) {
|
|
117478
|
+
await writeLine(ctx, import_picocolors11.default.dim(` …and ${result.flags.length - 15} more — see REWRITE_NOTES.md`));
|
|
117479
|
+
}
|
|
117480
|
+
}
|
|
117481
|
+
if (result.skipped.length > 0) {
|
|
117482
|
+
await writeLine(ctx, import_picocolors11.default.dim(`
|
|
117483
|
+
${result.skipped.length} file(s) couldn't be parsed and were skipped — listed in REWRITE_NOTES.md.`));
|
|
117484
|
+
}
|
|
117485
|
+
await writeLine(ctx, "");
|
|
117486
|
+
if (result.mode === "apply") {
|
|
117487
|
+
await writeLine(ctx, import_picocolors11.default.dim(result.changedCount > 0 ? "Files rewritten in place. Originals are in ./migration-preview/backup/ — diff against them (or git) before committing." : "No files were rewritten — the work left is the manual review above."));
|
|
117488
|
+
} else {
|
|
117489
|
+
await writeLine(ctx, import_picocolors11.default.dim(result.changedCount > 0 ? "Preview only — diff ./migration-preview/rewritten/ against your project, then re-run with --rewrite-client --apply to write in place." : "Preview only — no files needed automatic rewriting; work through the manual review above."));
|
|
117490
|
+
}
|
|
115650
117491
|
}
|
|
115651
117492
|
|
|
115652
117493
|
// src/commands/sharing.ts
|
|
@@ -115871,16 +117712,16 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
115871
117712
|
}
|
|
115872
117713
|
|
|
115873
117714
|
// src/open.ts
|
|
115874
|
-
import { spawn
|
|
117715
|
+
import { spawn } from "node:child_process";
|
|
115875
117716
|
async function openUrl(url2) {
|
|
115876
117717
|
const platform = process.platform;
|
|
115877
117718
|
try {
|
|
115878
117719
|
if (platform === "darwin")
|
|
115879
|
-
|
|
117720
|
+
spawn("open", [url2], { detached: true, stdio: "ignore" }).unref();
|
|
115880
117721
|
else if (platform === "win32")
|
|
115881
|
-
|
|
117722
|
+
spawn("cmd", ["/c", "start", "", url2], { detached: true, stdio: "ignore" }).unref();
|
|
115882
117723
|
else
|
|
115883
|
-
|
|
117724
|
+
spawn("xdg-open", [url2], { detached: true, stdio: "ignore" }).unref();
|
|
115884
117725
|
} catch {}
|
|
115885
117726
|
}
|
|
115886
117727
|
|
|
@@ -115987,7 +117828,7 @@ async function renderError(stderr, error48) {
|
|
|
115987
117828
|
// package.json
|
|
115988
117829
|
var package_default = {
|
|
115989
117830
|
name: "percher",
|
|
115990
|
-
version: "0.5.
|
|
117831
|
+
version: "0.5.7",
|
|
115991
117832
|
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
115992
117833
|
type: "module",
|
|
115993
117834
|
bin: {
|
|
@@ -116069,9 +117910,9 @@ async function showTelemetryNotice() {
|
|
|
116069
117910
|
return;
|
|
116070
117911
|
const { homedir: homedir2 } = await import("node:os");
|
|
116071
117912
|
const { existsSync: existsSync17, mkdirSync: mkdirSync6, writeFileSync: writeFileSync10 } = await import("node:fs");
|
|
116072
|
-
const { join:
|
|
116073
|
-
const configDir =
|
|
116074
|
-
const markerFile =
|
|
117913
|
+
const { join: join26 } = await import("node:path");
|
|
117914
|
+
const configDir = join26(homedir2(), ".percher");
|
|
117915
|
+
const markerFile = join26(configDir, ".telemetry-notice-shown");
|
|
116075
117916
|
if (existsSync17(markerFile))
|
|
116076
117917
|
return;
|
|
116077
117918
|
console.log("Percher sends non-account-linked usage stats (command, result, error type, OS, Bun version).");
|