@softr/cli 0.1.4 → 0.1.6-se21219.17
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/README.md +32 -9
- package/dist/cli.mjs +961 -185
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -1745,7 +1745,7 @@ var require_table = __commonJS({
|
|
|
1745
1745
|
var debug = require_debug();
|
|
1746
1746
|
var utils = require_utils();
|
|
1747
1747
|
var tableLayout = require_layout_manager();
|
|
1748
|
-
var
|
|
1748
|
+
var Table9 = class extends Array {
|
|
1749
1749
|
constructor(opts) {
|
|
1750
1750
|
super();
|
|
1751
1751
|
const options = utils.mergeOptions(opts);
|
|
@@ -1820,7 +1820,7 @@ var require_table = __commonJS({
|
|
|
1820
1820
|
return str[0].length;
|
|
1821
1821
|
}
|
|
1822
1822
|
};
|
|
1823
|
-
|
|
1823
|
+
Table9.reset = () => debug.reset();
|
|
1824
1824
|
function doDraw(row, lineNum, result) {
|
|
1825
1825
|
let line = [];
|
|
1826
1826
|
row.forEach(function(cell) {
|
|
@@ -1829,7 +1829,7 @@ var require_table = __commonJS({
|
|
|
1829
1829
|
let str = line.join("");
|
|
1830
1830
|
if (str.length) result.push(str);
|
|
1831
1831
|
}
|
|
1832
|
-
module.exports =
|
|
1832
|
+
module.exports = Table9;
|
|
1833
1833
|
}
|
|
1834
1834
|
});
|
|
1835
1835
|
|
|
@@ -2598,14 +2598,14 @@ var Option = class {
|
|
|
2598
2598
|
* @param {string} flags
|
|
2599
2599
|
* @param {string} [description]
|
|
2600
2600
|
*/
|
|
2601
|
-
constructor(
|
|
2602
|
-
this.flags =
|
|
2601
|
+
constructor(flags2, description) {
|
|
2602
|
+
this.flags = flags2;
|
|
2603
2603
|
this.description = description || "";
|
|
2604
|
-
this.required =
|
|
2605
|
-
this.optional =
|
|
2606
|
-
this.variadic = /\w\.\.\.[>\]]$/.test(
|
|
2604
|
+
this.required = flags2.includes("<");
|
|
2605
|
+
this.optional = flags2.includes("[");
|
|
2606
|
+
this.variadic = /\w\.\.\.[>\]]$/.test(flags2);
|
|
2607
2607
|
this.mandatory = false;
|
|
2608
|
-
const optionFlags = splitOptionFlags(
|
|
2608
|
+
const optionFlags = splitOptionFlags(flags2);
|
|
2609
2609
|
this.short = optionFlags.shortFlag;
|
|
2610
2610
|
this.long = optionFlags.longFlag;
|
|
2611
2611
|
this.negate = false;
|
|
@@ -2661,8 +2661,8 @@ var Option = class {
|
|
|
2661
2661
|
* @param {(string | string[])} names
|
|
2662
2662
|
* @return {Option}
|
|
2663
2663
|
*/
|
|
2664
|
-
conflicts(
|
|
2665
|
-
this.conflictsWith = this.conflictsWith.concat(
|
|
2664
|
+
conflicts(names2) {
|
|
2665
|
+
this.conflictsWith = this.conflictsWith.concat(names2);
|
|
2666
2666
|
return this;
|
|
2667
2667
|
}
|
|
2668
2668
|
/**
|
|
@@ -2856,12 +2856,12 @@ function camelcase(str) {
|
|
|
2856
2856
|
return str2 + word[0].toUpperCase() + word.slice(1);
|
|
2857
2857
|
});
|
|
2858
2858
|
}
|
|
2859
|
-
function splitOptionFlags(
|
|
2859
|
+
function splitOptionFlags(flags2) {
|
|
2860
2860
|
let shortFlag;
|
|
2861
2861
|
let longFlag;
|
|
2862
2862
|
const shortFlagExp = /^-[^-]$/;
|
|
2863
2863
|
const longFlagExp = /^--[^-]/;
|
|
2864
|
-
const flagParts =
|
|
2864
|
+
const flagParts = flags2.split(/[ |,]+/).concat("guard");
|
|
2865
2865
|
if (shortFlagExp.test(flagParts[0])) shortFlag = flagParts.shift();
|
|
2866
2866
|
if (longFlagExp.test(flagParts[0])) longFlag = flagParts.shift();
|
|
2867
2867
|
if (!shortFlag && shortFlagExp.test(flagParts[0]))
|
|
@@ -2872,7 +2872,7 @@ function splitOptionFlags(flags) {
|
|
|
2872
2872
|
}
|
|
2873
2873
|
if (flagParts[0].startsWith("-")) {
|
|
2874
2874
|
const unsupportedFlag = flagParts[0];
|
|
2875
|
-
const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${
|
|
2875
|
+
const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags2}'`;
|
|
2876
2876
|
if (/^-[^-][^-]/.test(unsupportedFlag))
|
|
2877
2877
|
throw new Error(
|
|
2878
2878
|
`${baseError}
|
|
@@ -2891,7 +2891,7 @@ function splitOptionFlags(flags) {
|
|
|
2891
2891
|
}
|
|
2892
2892
|
if (shortFlag === void 0 && longFlag === void 0)
|
|
2893
2893
|
throw new Error(
|
|
2894
|
-
`option creation failed due to no flags found in '${
|
|
2894
|
+
`option creation failed due to no flags found in '${flags2}'.`
|
|
2895
2895
|
);
|
|
2896
2896
|
return { shortFlag, longFlag };
|
|
2897
2897
|
}
|
|
@@ -3268,8 +3268,8 @@ var Command = class _Command extends EventEmitter {
|
|
|
3268
3268
|
* @param {string} names
|
|
3269
3269
|
* @return {Command} `this` command for chaining
|
|
3270
3270
|
*/
|
|
3271
|
-
arguments(
|
|
3272
|
-
|
|
3271
|
+
arguments(names2) {
|
|
3272
|
+
names2.trim().split(/ +/).forEach((detail) => {
|
|
3273
3273
|
this.argument(detail);
|
|
3274
3274
|
});
|
|
3275
3275
|
return this;
|
|
@@ -3454,8 +3454,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3454
3454
|
* @param {string} [description]
|
|
3455
3455
|
* @return {Option} new option
|
|
3456
3456
|
*/
|
|
3457
|
-
createOption(
|
|
3458
|
-
return new Option(
|
|
3457
|
+
createOption(flags2, description) {
|
|
3458
|
+
return new Option(flags2, description);
|
|
3459
3459
|
}
|
|
3460
3460
|
/**
|
|
3461
3461
|
* Wrap parseArgs to catch 'commander.invalidArgument'.
|
|
@@ -3570,13 +3570,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3570
3570
|
* @return {Command} `this` command for chaining
|
|
3571
3571
|
* @private
|
|
3572
3572
|
*/
|
|
3573
|
-
_optionEx(config,
|
|
3574
|
-
if (typeof
|
|
3573
|
+
_optionEx(config, flags2, description, fn, defaultValue) {
|
|
3574
|
+
if (typeof flags2 === "object" && flags2 instanceof Option) {
|
|
3575
3575
|
throw new Error(
|
|
3576
3576
|
"To add an Option object use addOption() instead of option() or requiredOption()"
|
|
3577
3577
|
);
|
|
3578
3578
|
}
|
|
3579
|
-
const option = this.createOption(
|
|
3579
|
+
const option = this.createOption(flags2, description);
|
|
3580
3580
|
option.makeOptionMandatory(!!config.mandatory);
|
|
3581
3581
|
if (typeof fn === "function") {
|
|
3582
3582
|
option.default(defaultValue).argParser(fn);
|
|
@@ -3613,8 +3613,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3613
3613
|
* @param {*} [defaultValue]
|
|
3614
3614
|
* @return {Command} `this` command for chaining
|
|
3615
3615
|
*/
|
|
3616
|
-
option(
|
|
3617
|
-
return this._optionEx({},
|
|
3616
|
+
option(flags2, description, parseArg, defaultValue) {
|
|
3617
|
+
return this._optionEx({}, flags2, description, parseArg, defaultValue);
|
|
3618
3618
|
}
|
|
3619
3619
|
/**
|
|
3620
3620
|
* Add a required option which must have a value after parsing. This usually means
|
|
@@ -3628,10 +3628,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3628
3628
|
* @param {*} [defaultValue]
|
|
3629
3629
|
* @return {Command} `this` command for chaining
|
|
3630
3630
|
*/
|
|
3631
|
-
requiredOption(
|
|
3631
|
+
requiredOption(flags2, description, parseArg, defaultValue) {
|
|
3632
3632
|
return this._optionEx(
|
|
3633
3633
|
{ mandatory: true },
|
|
3634
|
-
|
|
3634
|
+
flags2,
|
|
3635
3635
|
description,
|
|
3636
3636
|
parseArg,
|
|
3637
3637
|
defaultValue
|
|
@@ -3798,18 +3798,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3798
3798
|
*
|
|
3799
3799
|
* @private
|
|
3800
3800
|
*/
|
|
3801
|
-
_prepareUserArgs(argv,
|
|
3801
|
+
_prepareUserArgs(argv, parseOptions2) {
|
|
3802
3802
|
if (argv !== void 0 && !Array.isArray(argv)) {
|
|
3803
3803
|
throw new Error("first parameter to parse must be array or undefined");
|
|
3804
3804
|
}
|
|
3805
|
-
|
|
3806
|
-
if (argv === void 0 &&
|
|
3805
|
+
parseOptions2 = parseOptions2 || {};
|
|
3806
|
+
if (argv === void 0 && parseOptions2.from === void 0) {
|
|
3807
3807
|
if (process2.versions?.electron) {
|
|
3808
|
-
|
|
3808
|
+
parseOptions2.from = "electron";
|
|
3809
3809
|
}
|
|
3810
3810
|
const execArgv = process2.execArgv ?? [];
|
|
3811
3811
|
if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
|
|
3812
|
-
|
|
3812
|
+
parseOptions2.from = "eval";
|
|
3813
3813
|
}
|
|
3814
3814
|
}
|
|
3815
3815
|
if (argv === void 0) {
|
|
@@ -3817,7 +3817,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3817
3817
|
}
|
|
3818
3818
|
this.rawArgs = argv.slice();
|
|
3819
3819
|
let userArgs;
|
|
3820
|
-
switch (
|
|
3820
|
+
switch (parseOptions2.from) {
|
|
3821
3821
|
case void 0:
|
|
3822
3822
|
case "node":
|
|
3823
3823
|
this._scriptPath = argv[1];
|
|
@@ -3839,7 +3839,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3839
3839
|
break;
|
|
3840
3840
|
default:
|
|
3841
3841
|
throw new Error(
|
|
3842
|
-
`unexpected parse option { from: '${
|
|
3842
|
+
`unexpected parse option { from: '${parseOptions2.from}' }`
|
|
3843
3843
|
);
|
|
3844
3844
|
}
|
|
3845
3845
|
if (!this._name && this._scriptPath)
|
|
@@ -3869,9 +3869,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3869
3869
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
3870
3870
|
* @return {Command} `this` command for chaining
|
|
3871
3871
|
*/
|
|
3872
|
-
parse(argv,
|
|
3872
|
+
parse(argv, parseOptions2) {
|
|
3873
3873
|
this._prepareForParse();
|
|
3874
|
-
const userArgs = this._prepareUserArgs(argv,
|
|
3874
|
+
const userArgs = this._prepareUserArgs(argv, parseOptions2);
|
|
3875
3875
|
this._parseCommand([], userArgs);
|
|
3876
3876
|
return this;
|
|
3877
3877
|
}
|
|
@@ -3895,9 +3895,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3895
3895
|
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
|
|
3896
3896
|
* @return {Promise}
|
|
3897
3897
|
*/
|
|
3898
|
-
async parseAsync(argv,
|
|
3898
|
+
async parseAsync(argv, parseOptions2) {
|
|
3899
3899
|
this._prepareForParse();
|
|
3900
|
-
const userArgs = this._prepareUserArgs(argv,
|
|
3900
|
+
const userArgs = this._prepareUserArgs(argv, parseOptions2);
|
|
3901
3901
|
await this._parseCommand([], userArgs);
|
|
3902
3902
|
return this;
|
|
3903
3903
|
}
|
|
@@ -4748,12 +4748,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4748
4748
|
* @param {string} [description]
|
|
4749
4749
|
* @return {(this | string | undefined)} `this` command for chaining, or version string if no arguments
|
|
4750
4750
|
*/
|
|
4751
|
-
version(str,
|
|
4751
|
+
version(str, flags2, description) {
|
|
4752
4752
|
if (str === void 0) return this._version;
|
|
4753
4753
|
this._version = str;
|
|
4754
|
-
|
|
4754
|
+
flags2 = flags2 || "-V, --version";
|
|
4755
4755
|
description = description || "output the version number";
|
|
4756
|
-
const versionOption = this.createOption(
|
|
4756
|
+
const versionOption = this.createOption(flags2, description);
|
|
4757
4757
|
this._versionOptionName = versionOption.attributeName();
|
|
4758
4758
|
this._registerOption(versionOption);
|
|
4759
4759
|
this.on("option:" + versionOption.name(), () => {
|
|
@@ -4951,9 +4951,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
4951
4951
|
* @param {string} [path]
|
|
4952
4952
|
* @return {(string|null|Command)}
|
|
4953
4953
|
*/
|
|
4954
|
-
executableDir(
|
|
4955
|
-
if (
|
|
4956
|
-
this._executableDir =
|
|
4954
|
+
executableDir(path16) {
|
|
4955
|
+
if (path16 === void 0) return this._executableDir;
|
|
4956
|
+
this._executableDir = path16;
|
|
4957
4957
|
return this;
|
|
4958
4958
|
}
|
|
4959
4959
|
/**
|
|
@@ -5055,9 +5055,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
5055
5055
|
* @param {string} [description]
|
|
5056
5056
|
* @return {Command} `this` command for chaining
|
|
5057
5057
|
*/
|
|
5058
|
-
helpOption(
|
|
5059
|
-
if (typeof
|
|
5060
|
-
if (
|
|
5058
|
+
helpOption(flags2, description) {
|
|
5059
|
+
if (typeof flags2 === "boolean") {
|
|
5060
|
+
if (flags2) {
|
|
5061
5061
|
if (this._helpOption === null) this._helpOption = void 0;
|
|
5062
5062
|
if (this._defaultOptionGroup) {
|
|
5063
5063
|
this._initOptionGroup(this._getHelpOption());
|
|
@@ -5068,10 +5068,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
5068
5068
|
return this;
|
|
5069
5069
|
}
|
|
5070
5070
|
this._helpOption = this.createOption(
|
|
5071
|
-
|
|
5071
|
+
flags2 ?? "-h, --help",
|
|
5072
5072
|
description ?? "display help for command"
|
|
5073
5073
|
);
|
|
5074
|
-
if (
|
|
5074
|
+
if (flags2 || description) this._initOptionGroup(this._helpOption);
|
|
5075
5075
|
return this;
|
|
5076
5076
|
}
|
|
5077
5077
|
/**
|
|
@@ -5310,12 +5310,12 @@ function executionOrder(config) {
|
|
|
5310
5310
|
collect(config.actions, []);
|
|
5311
5311
|
const outgoing = new Map(appearance.map((id) => [id, []]));
|
|
5312
5312
|
const indegree = new Map(appearance.map((id) => [id, 0]));
|
|
5313
|
-
for (const
|
|
5314
|
-
const to =
|
|
5315
|
-
if (!to || !nodes.has(
|
|
5313
|
+
for (const path16 of pathSets.flat()) {
|
|
5314
|
+
const to = path16.toActionId;
|
|
5315
|
+
if (!to || !nodes.has(path16.fromActionId) || !nodes.has(to) || outgoing.get(path16.fromActionId).includes(to)) {
|
|
5316
5316
|
continue;
|
|
5317
5317
|
}
|
|
5318
|
-
outgoing.get(
|
|
5318
|
+
outgoing.get(path16.fromActionId).push(to);
|
|
5319
5319
|
indegree.set(to, indegree.get(to) + 1);
|
|
5320
5320
|
}
|
|
5321
5321
|
const queue = [...nodes.values()].filter((node) => node.kind === "trigger").map((node) => node.id);
|
|
@@ -6130,43 +6130,45 @@ var BASE_URLS = {
|
|
|
6130
6130
|
studio: (target) => target.studioApiUrl,
|
|
6131
6131
|
tables: (target) => target.tablesApiUrl
|
|
6132
6132
|
};
|
|
6133
|
-
async function send(client, service, method,
|
|
6133
|
+
async function send(client, service, method, path16, body) {
|
|
6134
6134
|
const init = {
|
|
6135
6135
|
method,
|
|
6136
6136
|
headers: { ...authHeaders(client, service), Accept: "application/json" }
|
|
6137
6137
|
};
|
|
6138
|
-
if (body
|
|
6138
|
+
if (body instanceof FormData) {
|
|
6139
|
+
init.body = body;
|
|
6140
|
+
} else if (body !== void 0) {
|
|
6139
6141
|
init.headers = { ...init.headers, "Content-Type": "application/json" };
|
|
6140
6142
|
init.body = JSON.stringify(body);
|
|
6141
6143
|
}
|
|
6142
|
-
const response = await fetch(`${BASE_URLS[service](client.target)}${
|
|
6144
|
+
const response = await fetch(`${BASE_URLS[service](client.target)}${path16}`, init);
|
|
6143
6145
|
if (response.ok) {
|
|
6144
6146
|
return response;
|
|
6145
6147
|
}
|
|
6146
6148
|
const text = await response.text();
|
|
6147
6149
|
throw new SoftrApiError(
|
|
6148
|
-
`${method} ${
|
|
6150
|
+
`${method} ${path16} failed with status ${response.status}${text ? `: ${text}` : ""}`,
|
|
6149
6151
|
response.status,
|
|
6150
6152
|
text,
|
|
6151
6153
|
hintFor(response.status, client, service)
|
|
6152
6154
|
);
|
|
6153
6155
|
}
|
|
6154
|
-
async function apiRequest(client, method,
|
|
6155
|
-
const response = await send(client, "workflows", method,
|
|
6156
|
+
async function apiRequest(client, method, path16, body) {
|
|
6157
|
+
const response = await send(client, "workflows", method, path16, body);
|
|
6156
6158
|
return await response.json();
|
|
6157
6159
|
}
|
|
6158
|
-
async function apiRequestVoid(client, method,
|
|
6159
|
-
await send(client, "workflows", method,
|
|
6160
|
+
async function apiRequestVoid(client, method, path16, body) {
|
|
6161
|
+
await send(client, "workflows", method, path16, body);
|
|
6160
6162
|
}
|
|
6161
|
-
async function tablesRequest(client, method,
|
|
6162
|
-
const response = await send(client, "tables", method,
|
|
6163
|
+
async function tablesRequest(client, method, path16, body) {
|
|
6164
|
+
const response = await send(client, "tables", method, path16, body);
|
|
6163
6165
|
return await response.json();
|
|
6164
6166
|
}
|
|
6165
|
-
async function tablesRequestVoid(client, method,
|
|
6166
|
-
await send(client, "tables", method,
|
|
6167
|
+
async function tablesRequestVoid(client, method, path16, body) {
|
|
6168
|
+
await send(client, "tables", method, path16, body);
|
|
6167
6169
|
}
|
|
6168
|
-
async function studioRequest(client, method,
|
|
6169
|
-
const response = await send(client, "studio", method,
|
|
6170
|
+
async function studioRequest(client, method, path16, body) {
|
|
6171
|
+
const response = await send(client, "studio", method, path16, body);
|
|
6170
6172
|
return await response.json();
|
|
6171
6173
|
}
|
|
6172
6174
|
|
|
@@ -6177,6 +6179,9 @@ function globalOptions(command) {
|
|
|
6177
6179
|
function emit(options, human, data2) {
|
|
6178
6180
|
process.stdout.write(options.json ? JSON.stringify(data2, null, 2) + "\n" : human + "\n");
|
|
6179
6181
|
}
|
|
6182
|
+
function plainTable(head, colWidths) {
|
|
6183
|
+
return { head, colWidths, wordWrap: true, style: { head: [], border: [], "padding-left": 1, "padding-right": 1 } };
|
|
6184
|
+
}
|
|
6180
6185
|
function reportError(error) {
|
|
6181
6186
|
if (error instanceof CliError || error instanceof SoftrApiError) {
|
|
6182
6187
|
process.stderr.write(`Error: ${error.message}
|
|
@@ -6989,12 +6994,12 @@ function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
|
6989
6994
|
}
|
|
6990
6995
|
return result;
|
|
6991
6996
|
}
|
|
6992
|
-
function findNodeAtLocation(root,
|
|
6997
|
+
function findNodeAtLocation(root, path16) {
|
|
6993
6998
|
if (!root) {
|
|
6994
6999
|
return void 0;
|
|
6995
7000
|
}
|
|
6996
7001
|
let node = root;
|
|
6997
|
-
for (let segment of
|
|
7002
|
+
for (let segment of path16) {
|
|
6998
7003
|
if (typeof segment === "string") {
|
|
6999
7004
|
if (node.type !== "object" || !Array.isArray(node.children)) {
|
|
7000
7005
|
return void 0;
|
|
@@ -7348,14 +7353,14 @@ function getNodeType(value) {
|
|
|
7348
7353
|
|
|
7349
7354
|
// node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
7350
7355
|
function setProperty(text, originalPath, value, options) {
|
|
7351
|
-
const
|
|
7356
|
+
const path16 = originalPath.slice();
|
|
7352
7357
|
const errors = [];
|
|
7353
7358
|
const root = parseTree(text, errors);
|
|
7354
7359
|
let parent = void 0;
|
|
7355
7360
|
let lastSegment = void 0;
|
|
7356
|
-
while (
|
|
7357
|
-
lastSegment =
|
|
7358
|
-
parent = findNodeAtLocation(root,
|
|
7361
|
+
while (path16.length > 0) {
|
|
7362
|
+
lastSegment = path16.pop();
|
|
7363
|
+
parent = findNodeAtLocation(root, path16);
|
|
7359
7364
|
if (parent === void 0 && value !== void 0) {
|
|
7360
7365
|
if (typeof lastSegment === "string") {
|
|
7361
7366
|
value = { [lastSegment]: value };
|
|
@@ -7578,8 +7583,8 @@ function printParseErrorCode(code) {
|
|
|
7578
7583
|
}
|
|
7579
7584
|
return "<unknown ParseErrorCode>";
|
|
7580
7585
|
}
|
|
7581
|
-
function modify(text,
|
|
7582
|
-
return setProperty(text,
|
|
7586
|
+
function modify(text, path16, value, options) {
|
|
7587
|
+
return setProperty(text, path16, value, options);
|
|
7583
7588
|
}
|
|
7584
7589
|
function applyEdits(text, edits) {
|
|
7585
7590
|
let sortedEdits = edits.slice(0).sort((a, b) => {
|
|
@@ -7636,8 +7641,8 @@ function parseJsoncFile(file, text) {
|
|
|
7636
7641
|
async function listSubdirsWith(cwd, holds) {
|
|
7637
7642
|
const entries = await readdir(cwd, { withFileTypes: true });
|
|
7638
7643
|
const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => path2.join(cwd, entry.name));
|
|
7639
|
-
const
|
|
7640
|
-
return dirs.filter((_, index) =>
|
|
7644
|
+
const flags2 = await Promise.all(dirs.map((dir) => holds(dir)));
|
|
7645
|
+
return dirs.filter((_, index) => flags2[index]);
|
|
7641
7646
|
}
|
|
7642
7647
|
async function readConfig(dir) {
|
|
7643
7648
|
const file = configPath(dir);
|
|
@@ -8284,12 +8289,12 @@ prototypeAccessors.inAsync.get = function() {
|
|
|
8284
8289
|
prototypeAccessors.canAwait.get = function() {
|
|
8285
8290
|
for (var i2 = this.scopeStack.length - 1; i2 >= 0; i2--) {
|
|
8286
8291
|
var ref2 = this.scopeStack[i2];
|
|
8287
|
-
var
|
|
8288
|
-
if (
|
|
8292
|
+
var flags2 = ref2.flags;
|
|
8293
|
+
if (flags2 & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT)) {
|
|
8289
8294
|
return false;
|
|
8290
8295
|
}
|
|
8291
|
-
if (
|
|
8292
|
-
return (
|
|
8296
|
+
if (flags2 & SCOPE_FUNCTION) {
|
|
8297
|
+
return (flags2 & SCOPE_ASYNC) > 0;
|
|
8293
8298
|
}
|
|
8294
8299
|
}
|
|
8295
8300
|
return this.inModule && this.options.ecmaVersion >= 13 || this.options.allowAwaitOutsideFunction;
|
|
@@ -8305,8 +8310,8 @@ prototypeAccessors.allowReturn.get = function() {
|
|
|
8305
8310
|
};
|
|
8306
8311
|
prototypeAccessors.allowSuper.get = function() {
|
|
8307
8312
|
var ref2 = this.currentThisScope();
|
|
8308
|
-
var
|
|
8309
|
-
return (
|
|
8313
|
+
var flags2 = ref2.flags;
|
|
8314
|
+
return (flags2 & SCOPE_SUPER) > 0 || this.options.allowSuperOutsideMethod;
|
|
8310
8315
|
};
|
|
8311
8316
|
prototypeAccessors.allowDirectSuper.get = function() {
|
|
8312
8317
|
return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0;
|
|
@@ -8317,8 +8322,8 @@ prototypeAccessors.treatFunctionsAsVar.get = function() {
|
|
|
8317
8322
|
prototypeAccessors.allowNewDotTarget.get = function() {
|
|
8318
8323
|
for (var i2 = this.scopeStack.length - 1; i2 >= 0; i2--) {
|
|
8319
8324
|
var ref2 = this.scopeStack[i2];
|
|
8320
|
-
var
|
|
8321
|
-
if (
|
|
8325
|
+
var flags2 = ref2.flags;
|
|
8326
|
+
if (flags2 & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT) || flags2 & SCOPE_FUNCTION && !(flags2 & SCOPE_ARROW)) {
|
|
8322
8327
|
return true;
|
|
8323
8328
|
}
|
|
8324
8329
|
}
|
|
@@ -8326,11 +8331,11 @@ prototypeAccessors.allowNewDotTarget.get = function() {
|
|
|
8326
8331
|
};
|
|
8327
8332
|
prototypeAccessors.allowUsing.get = function() {
|
|
8328
8333
|
var ref2 = this.currentScope();
|
|
8329
|
-
var
|
|
8330
|
-
if (
|
|
8334
|
+
var flags2 = ref2.flags;
|
|
8335
|
+
if (flags2 & SCOPE_SWITCH) {
|
|
8331
8336
|
return false;
|
|
8332
8337
|
}
|
|
8333
|
-
if (!this.inModule &&
|
|
8338
|
+
if (!this.inModule && flags2 & SCOPE_TOP) {
|
|
8334
8339
|
return false;
|
|
8335
8340
|
}
|
|
8336
8341
|
return true;
|
|
@@ -11111,14 +11116,14 @@ pp$4.curPosition = function() {
|
|
|
11111
11116
|
}
|
|
11112
11117
|
};
|
|
11113
11118
|
var pp$3 = Parser.prototype;
|
|
11114
|
-
var Scope = function Scope2(
|
|
11115
|
-
this.flags =
|
|
11119
|
+
var Scope = function Scope2(flags2) {
|
|
11120
|
+
this.flags = flags2;
|
|
11116
11121
|
this.var = [];
|
|
11117
11122
|
this.lexical = [];
|
|
11118
11123
|
this.functions = [];
|
|
11119
11124
|
};
|
|
11120
|
-
pp$3.enterScope = function(
|
|
11121
|
-
this.scopeStack.push(new Scope(
|
|
11125
|
+
pp$3.enterScope = function(flags2) {
|
|
11126
|
+
this.scopeStack.push(new Scope(flags2));
|
|
11122
11127
|
};
|
|
11123
11128
|
pp$3.exitScope = function() {
|
|
11124
11129
|
this.scopeStack.pop();
|
|
@@ -11334,12 +11339,12 @@ var RegExpValidationState = function RegExpValidationState2(parser) {
|
|
|
11334
11339
|
this.backReferenceNames = [];
|
|
11335
11340
|
this.branchID = null;
|
|
11336
11341
|
};
|
|
11337
|
-
RegExpValidationState.prototype.reset = function reset(start, pattern,
|
|
11338
|
-
var unicodeSets =
|
|
11339
|
-
var unicode =
|
|
11342
|
+
RegExpValidationState.prototype.reset = function reset(start, pattern, flags2) {
|
|
11343
|
+
var unicodeSets = flags2.indexOf("v") !== -1;
|
|
11344
|
+
var unicode = flags2.indexOf("u") !== -1;
|
|
11340
11345
|
this.start = start | 0;
|
|
11341
11346
|
this.source = pattern + "";
|
|
11342
|
-
this.flags =
|
|
11347
|
+
this.flags = flags2;
|
|
11343
11348
|
if (unicodeSets && this.parser.options.ecmaVersion >= 15) {
|
|
11344
11349
|
this.switchU = true;
|
|
11345
11350
|
this.switchV = true;
|
|
@@ -11416,15 +11421,15 @@ RegExpValidationState.prototype.eatChars = function eatChars(chs, forceU) {
|
|
|
11416
11421
|
};
|
|
11417
11422
|
pp$1.validateRegExpFlags = function(state) {
|
|
11418
11423
|
var validFlags = state.validFlags;
|
|
11419
|
-
var
|
|
11424
|
+
var flags2 = state.flags;
|
|
11420
11425
|
var u = false;
|
|
11421
11426
|
var v = false;
|
|
11422
|
-
for (var i2 = 0; i2 <
|
|
11423
|
-
var flag =
|
|
11427
|
+
for (var i2 = 0; i2 < flags2.length; i2++) {
|
|
11428
|
+
var flag = flags2.charAt(i2);
|
|
11424
11429
|
if (validFlags.indexOf(flag) === -1) {
|
|
11425
11430
|
this.raise(state.start, "Invalid regular expression flag");
|
|
11426
11431
|
}
|
|
11427
|
-
if (
|
|
11432
|
+
if (flags2.indexOf(flag, i2 + 1) > -1) {
|
|
11428
11433
|
this.raise(state.start, "Duplicate regular expression flag");
|
|
11429
11434
|
}
|
|
11430
11435
|
if (flag === "u") {
|
|
@@ -13036,20 +13041,20 @@ pp.readRegexp = function() {
|
|
|
13036
13041
|
var pattern = this.input.slice(start, this.pos);
|
|
13037
13042
|
++this.pos;
|
|
13038
13043
|
var flagsStart = this.pos;
|
|
13039
|
-
var
|
|
13044
|
+
var flags2 = this.readWord1();
|
|
13040
13045
|
if (this.containsEsc) {
|
|
13041
13046
|
this.unexpected(flagsStart);
|
|
13042
13047
|
}
|
|
13043
13048
|
var state = this.regexpState || (this.regexpState = new RegExpValidationState(this));
|
|
13044
|
-
state.reset(start, pattern,
|
|
13049
|
+
state.reset(start, pattern, flags2);
|
|
13045
13050
|
this.validateRegExpFlags(state);
|
|
13046
13051
|
this.validateRegExpPattern(state);
|
|
13047
13052
|
var value = null;
|
|
13048
13053
|
try {
|
|
13049
|
-
value = new RegExp(pattern,
|
|
13054
|
+
value = new RegExp(pattern, flags2);
|
|
13050
13055
|
} catch (e) {
|
|
13051
13056
|
}
|
|
13052
|
-
return this.finishToken(types$1.regexp, { pattern, flags, value });
|
|
13057
|
+
return this.finishToken(types$1.regexp, { pattern, flags: flags2, value });
|
|
13053
13058
|
};
|
|
13054
13059
|
pp.readInt = function(radix, len, maybeLegacyOctalNumericLiteral) {
|
|
13055
13060
|
var allowSeparators = this.options.ecmaVersion >= 12 && len === void 0;
|
|
@@ -13590,8 +13595,8 @@ function typeOfField(field) {
|
|
|
13590
13595
|
return field.allowMultipleEntries ? arrayOf(base) : base;
|
|
13591
13596
|
}
|
|
13592
13597
|
var SEGMENT = /^(?:\.?\[\s*'((?:[^'\\]|\\.)*)'\s*\]|\.?\[\s*"((?:[^"\\]|\\.)*)"\s*\]|\.?\[\s*(\d+)\s*\]|\.?\[\s*\*\s*\]|\.([^.[\]]+))/;
|
|
13593
|
-
function parsePath(
|
|
13594
|
-
let rest =
|
|
13598
|
+
function parsePath(path16) {
|
|
13599
|
+
let rest = path16.trim();
|
|
13595
13600
|
if (rest.startsWith("$")) {
|
|
13596
13601
|
rest = rest.slice(1);
|
|
13597
13602
|
}
|
|
@@ -14091,10 +14096,10 @@ function describePlaceholder(placeholder, raw, config, outputs, depth) {
|
|
|
14091
14096
|
function untested(nodeId) {
|
|
14092
14097
|
return `node "${nodeId}" has no test output yet (run: softr workflows test ${nodeId})`;
|
|
14093
14098
|
}
|
|
14094
|
-
function describeOutputRef(nodeId,
|
|
14095
|
-
const segments = parsePath(
|
|
14099
|
+
function describeOutputRef(nodeId, path16, source, outputs) {
|
|
14100
|
+
const segments = parsePath(path16);
|
|
14096
14101
|
if (!segments) {
|
|
14097
|
-
return { type: UNKNOWN, source, verified: false, note: `unsupported path "${
|
|
14102
|
+
return { type: UNKNOWN, source, verified: false, note: `unsupported path "${path16}"` };
|
|
14098
14103
|
}
|
|
14099
14104
|
const row = outputs[nodeId];
|
|
14100
14105
|
if (!row) {
|
|
@@ -14575,6 +14580,103 @@ async function deleteDatabase(client, databaseId, force) {
|
|
|
14575
14580
|
async function listTables(client, databaseId) {
|
|
14576
14581
|
return (await tablesRequest(client, "GET", `${DATABASES}/${encodeURIComponent(databaseId)}/tables`)).data;
|
|
14577
14582
|
}
|
|
14583
|
+
function tablePath(databaseId, tableId) {
|
|
14584
|
+
const tables = `${DATABASES}/${encodeURIComponent(databaseId)}/tables`;
|
|
14585
|
+
return tableId ? `${tables}/${encodeURIComponent(tableId)}` : tables;
|
|
14586
|
+
}
|
|
14587
|
+
async function createTable(client, databaseId, table) {
|
|
14588
|
+
return (await tablesRequest(client, "POST", tablePath(databaseId), table)).data;
|
|
14589
|
+
}
|
|
14590
|
+
async function updateTable(client, databaseId, tableId, table) {
|
|
14591
|
+
return (await tablesRequest(client, "PUT", tablePath(databaseId, tableId), table)).data;
|
|
14592
|
+
}
|
|
14593
|
+
async function deleteTable(client, databaseId, tableId, force) {
|
|
14594
|
+
await tablesRequestVoid(client, "DELETE", `${tablePath(databaseId, tableId)}${force ? "?force=true" : ""}`);
|
|
14595
|
+
}
|
|
14596
|
+
async function addField(client, databaseId, tableId, field) {
|
|
14597
|
+
return (await tablesRequest(client, "POST", `${tablePath(databaseId, tableId)}/fields`, field)).data;
|
|
14598
|
+
}
|
|
14599
|
+
async function updateField(client, databaseId, tableId, fieldId, field) {
|
|
14600
|
+
return (await tablesRequest(
|
|
14601
|
+
client,
|
|
14602
|
+
"PUT",
|
|
14603
|
+
`${tablePath(databaseId, tableId)}/fields/${encodeURIComponent(fieldId)}`,
|
|
14604
|
+
field
|
|
14605
|
+
)).data;
|
|
14606
|
+
}
|
|
14607
|
+
async function deleteField(client, databaseId, tableId, fieldId) {
|
|
14608
|
+
await tablesRequestVoid(client, "DELETE", `${tablePath(databaseId, tableId)}/fields/${encodeURIComponent(fieldId)}`);
|
|
14609
|
+
}
|
|
14610
|
+
async function listViews(client, databaseId, tableId) {
|
|
14611
|
+
return (await tablesRequest(client, "GET", `${tablePath(databaseId, tableId)}/views`)).data;
|
|
14612
|
+
}
|
|
14613
|
+
function recordsPath(databaseId, tableId, recordId) {
|
|
14614
|
+
const records = `${tablePath(databaseId, tableId)}/records`;
|
|
14615
|
+
return recordId ? `${records}/${encodeURIComponent(recordId)}` : records;
|
|
14616
|
+
}
|
|
14617
|
+
function names(fieldNames) {
|
|
14618
|
+
return fieldNames ? "fieldNames=true" : "fieldNames=false";
|
|
14619
|
+
}
|
|
14620
|
+
async function listRecords(client, databaseId, tableId, query) {
|
|
14621
|
+
const params = new URLSearchParams({ offset: String(query.offset), limit: String(query.limit) });
|
|
14622
|
+
if (query.viewId) {
|
|
14623
|
+
params.set("viewId", query.viewId);
|
|
14624
|
+
}
|
|
14625
|
+
const response = await tablesRequest(
|
|
14626
|
+
client,
|
|
14627
|
+
"GET",
|
|
14628
|
+
`${recordsPath(databaseId, tableId)}?${params.toString()}&${names(query.fieldNames)}`
|
|
14629
|
+
);
|
|
14630
|
+
return { records: response.data, metadata: response.metadata };
|
|
14631
|
+
}
|
|
14632
|
+
async function searchRecords(client, databaseId, tableId, search, fieldNames) {
|
|
14633
|
+
const response = await tablesRequest(
|
|
14634
|
+
client,
|
|
14635
|
+
"POST",
|
|
14636
|
+
`${recordsPath(databaseId, tableId)}/search?${names(fieldNames)}`,
|
|
14637
|
+
search
|
|
14638
|
+
);
|
|
14639
|
+
return { records: response.data, metadata: response.metadata };
|
|
14640
|
+
}
|
|
14641
|
+
async function getRecord(client, databaseId, tableId, recordId, fieldNames) {
|
|
14642
|
+
return (await tablesRequest(
|
|
14643
|
+
client,
|
|
14644
|
+
"GET",
|
|
14645
|
+
`${recordsPath(databaseId, tableId, recordId)}?${names(fieldNames)}`
|
|
14646
|
+
)).data;
|
|
14647
|
+
}
|
|
14648
|
+
async function createRecord(client, databaseId, tableId, fields, fieldNames) {
|
|
14649
|
+
return (await tablesRequest(
|
|
14650
|
+
client,
|
|
14651
|
+
"POST",
|
|
14652
|
+
`${recordsPath(databaseId, tableId)}?${names(fieldNames)}`,
|
|
14653
|
+
{
|
|
14654
|
+
fields
|
|
14655
|
+
}
|
|
14656
|
+
)).data;
|
|
14657
|
+
}
|
|
14658
|
+
async function updateRecord(client, databaseId, tableId, recordId, fields, fieldNames) {
|
|
14659
|
+
return (await tablesRequest(
|
|
14660
|
+
client,
|
|
14661
|
+
"PATCH",
|
|
14662
|
+
`${recordsPath(databaseId, tableId, recordId)}?${names(fieldNames)}`,
|
|
14663
|
+
{ fields }
|
|
14664
|
+
)).data;
|
|
14665
|
+
}
|
|
14666
|
+
async function deleteRecord(client, databaseId, tableId, recordId) {
|
|
14667
|
+
await tablesRequestVoid(client, "DELETE", recordsPath(databaseId, tableId, recordId));
|
|
14668
|
+
}
|
|
14669
|
+
async function uploadAttachment(client, databaseId, tableId, recordId, fieldId, file) {
|
|
14670
|
+
const form = new FormData();
|
|
14671
|
+
form.set("file", new Blob([file.content]), file.name);
|
|
14672
|
+
form.set("fileName", file.name);
|
|
14673
|
+
return (await tablesRequest(
|
|
14674
|
+
client,
|
|
14675
|
+
"PUT",
|
|
14676
|
+
`${recordsPath(databaseId, tableId, recordId)}/fields/${encodeURIComponent(fieldId)}/upload-attachment`,
|
|
14677
|
+
form
|
|
14678
|
+
)).data;
|
|
14679
|
+
}
|
|
14578
14680
|
|
|
14579
14681
|
// src/config/credentials.ts
|
|
14580
14682
|
import { chmod, mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
@@ -14612,8 +14714,8 @@ function refreshFailureHint(status) {
|
|
|
14612
14714
|
return status === 401 ? "The OAuth grant is gone (revoked or older than 30 days). Run: softr login" : "The studio could not renew the login right now; try again in a moment.";
|
|
14613
14715
|
}
|
|
14614
14716
|
async function tokenRequest(target, form) {
|
|
14615
|
-
const
|
|
14616
|
-
const response = await fetch(`${target.studioApiUrl}${
|
|
14717
|
+
const path16 = "/v1/oauth/token";
|
|
14718
|
+
const response = await fetch(`${target.studioApiUrl}${path16}`, {
|
|
14617
14719
|
method: "POST",
|
|
14618
14720
|
headers: { "Content-Type": "application/x-www-form-urlencoded", Accept: "application/json" },
|
|
14619
14721
|
body: new URLSearchParams({ ...form, client_id: oauthClientId() }).toString()
|
|
@@ -14621,7 +14723,7 @@ async function tokenRequest(target, form) {
|
|
|
14621
14723
|
if (!response.ok) {
|
|
14622
14724
|
const text = await response.text();
|
|
14623
14725
|
throw new SoftrApiError(
|
|
14624
|
-
`POST ${
|
|
14726
|
+
`POST ${path16} failed with status ${response.status}${text ? `: ${text}` : ""}`,
|
|
14625
14727
|
response.status,
|
|
14626
14728
|
text,
|
|
14627
14729
|
form["grant_type"] === "refresh_token" ? refreshFailureHint(response.status) : void 0
|
|
@@ -14791,8 +14893,26 @@ async function authenticatedClient(target) {
|
|
|
14791
14893
|
}
|
|
14792
14894
|
|
|
14793
14895
|
// src/project/db-dir.ts
|
|
14794
|
-
import { mkdir as mkdir5, readFile as readFile6, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
14896
|
+
import { mkdir as mkdir5, readdir as readdir2, readFile as readFile6, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
14795
14897
|
import path8 from "node:path";
|
|
14898
|
+
|
|
14899
|
+
// src/project/lookup.ts
|
|
14900
|
+
function byIdOrName(items, reference, kind, describe2 = (item) => item.id) {
|
|
14901
|
+
const byId = items.find((item) => item.id === reference);
|
|
14902
|
+
if (byId) {
|
|
14903
|
+
return byId;
|
|
14904
|
+
}
|
|
14905
|
+
const byName = items.filter((item) => item.name === reference);
|
|
14906
|
+
if (byName.length > 1) {
|
|
14907
|
+
throw new CliError(
|
|
14908
|
+
`Several ${kind}s are named "${reference}".`,
|
|
14909
|
+
`Pass the id of one: ${byName.map(describe2).join(", ")}`
|
|
14910
|
+
);
|
|
14911
|
+
}
|
|
14912
|
+
return byName[0];
|
|
14913
|
+
}
|
|
14914
|
+
|
|
14915
|
+
// src/project/db-dir.ts
|
|
14796
14916
|
var DB_CONFIG_FILE_NAME = "softr-db.jsonc";
|
|
14797
14917
|
var DB_CACHE_DIR_NAME = ".softr-db";
|
|
14798
14918
|
var DATABASE_ID_ENV_VAR = "SOFTR_DATABASE_ID";
|
|
@@ -14841,8 +14961,41 @@ async function writeSchemaCache(dir, database, tables) {
|
|
|
14841
14961
|
const cache = { database, tables, refreshedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14842
14962
|
await mkdir5(path8.dirname(cacheFile(dir)), { recursive: true });
|
|
14843
14963
|
await writeFile6(cacheFile(dir), JSON.stringify(cache, null, 2) + "\n");
|
|
14964
|
+
await pruneViewsCache(dir, new Set(tables.map((table) => table.id)));
|
|
14844
14965
|
return cache;
|
|
14845
14966
|
}
|
|
14967
|
+
function viewsDir(dir) {
|
|
14968
|
+
return path8.join(dir, DB_CACHE_DIR_NAME, "views");
|
|
14969
|
+
}
|
|
14970
|
+
async function readViewsCache(dir, tableId) {
|
|
14971
|
+
try {
|
|
14972
|
+
return JSON.parse(await readFile6(path8.join(viewsDir(dir), `${tableId}.json`), "utf8"));
|
|
14973
|
+
} catch (error) {
|
|
14974
|
+
if (error.code === "ENOENT") {
|
|
14975
|
+
return void 0;
|
|
14976
|
+
}
|
|
14977
|
+
throw error;
|
|
14978
|
+
}
|
|
14979
|
+
}
|
|
14980
|
+
async function writeViewsCache(dir, tableId, views) {
|
|
14981
|
+
const value = { tableId, views, refreshedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14982
|
+
await mkdir5(viewsDir(dir), { recursive: true });
|
|
14983
|
+
await writeFile6(path8.join(viewsDir(dir), `${tableId}.json`), JSON.stringify(value, null, 2) + "\n");
|
|
14984
|
+
}
|
|
14985
|
+
async function pruneViewsCache(dir, tableIds) {
|
|
14986
|
+
let names2;
|
|
14987
|
+
try {
|
|
14988
|
+
names2 = await readdir2(viewsDir(dir));
|
|
14989
|
+
} catch (error) {
|
|
14990
|
+
if (error.code === "ENOENT") {
|
|
14991
|
+
return;
|
|
14992
|
+
}
|
|
14993
|
+
throw error;
|
|
14994
|
+
}
|
|
14995
|
+
await Promise.all(
|
|
14996
|
+
names2.filter((name) => name.endsWith(".json") && !tableIds.has(name.slice(0, -".json".length))).map((name) => rm(path8.join(viewsDir(dir), name), { force: true }))
|
|
14997
|
+
);
|
|
14998
|
+
}
|
|
14846
14999
|
async function refreshSchemaCache(client, dir, databaseId) {
|
|
14847
15000
|
const [database, tables] = await Promise.all([getDatabase(client, databaseId), listTables(client, databaseId)]);
|
|
14848
15001
|
return writeSchemaCache(dir, database, tables);
|
|
@@ -14903,25 +15056,19 @@ async function databaseDirFor(cwd, explicitDir, databaseId, dirName) {
|
|
|
14903
15056
|
return { dir: sibling2, existing: false };
|
|
14904
15057
|
}
|
|
14905
15058
|
async function findReachableDatabase(client, reference) {
|
|
14906
|
-
const
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
14910
|
-
|
|
14911
|
-
|
|
14912
|
-
if (
|
|
14913
|
-
throw new CliError(
|
|
14914
|
-
`Several databases are named "${reference}".`,
|
|
14915
|
-
`Pass the id of one: ${byName.map((database) => `${database.id} (workspace ${database.workspaceId})`).join(", ")}`
|
|
14916
|
-
);
|
|
14917
|
-
}
|
|
14918
|
-
if (!byName[0]) {
|
|
15059
|
+
const database = byIdOrName(
|
|
15060
|
+
await listDatabases(client),
|
|
15061
|
+
reference,
|
|
15062
|
+
"database",
|
|
15063
|
+
(item) => `${item.id} (workspace ${item.workspaceId})`
|
|
15064
|
+
);
|
|
15065
|
+
if (!database) {
|
|
14919
15066
|
throw new CliError(
|
|
14920
15067
|
`The token reaches no database with the id or name "${reference}".`,
|
|
14921
15068
|
'"softr db list" shows the ones it reaches.'
|
|
14922
15069
|
);
|
|
14923
15070
|
}
|
|
14924
|
-
return
|
|
15071
|
+
return database;
|
|
14925
15072
|
}
|
|
14926
15073
|
async function bindDatabaseDir(client, cwd, reference, explicitDir) {
|
|
14927
15074
|
const here = path8.resolve(cwd, explicitDir ?? ".");
|
|
@@ -14944,6 +15091,10 @@ async function bindDatabaseDir(client, cwd, reference, explicitDir) {
|
|
|
14944
15091
|
return { databaseId: database.id, dir, wrote: !existing };
|
|
14945
15092
|
}
|
|
14946
15093
|
|
|
15094
|
+
// src/commands/db/help.ts
|
|
15095
|
+
var DATABASE_ID_HELP = `the database id (default: $SOFTR_DATABASE_ID, else the one in ${DB_CONFIG_FILE_NAME})`;
|
|
15096
|
+
var DATABASE_DIR_HELP = `database directory, the one holding ${DB_CONFIG_FILE_NAME} (default: the current directory)`;
|
|
15097
|
+
|
|
14947
15098
|
// src/api/studio.ts
|
|
14948
15099
|
async function resolveTokenOwner(client) {
|
|
14949
15100
|
try {
|
|
@@ -15420,18 +15571,11 @@ Next: softr workflows add <TYPE> --dir ${path10.relative(cwd, dir) || "."} (see
|
|
|
15420
15571
|
}
|
|
15421
15572
|
|
|
15422
15573
|
// src/commands/db/databases.ts
|
|
15423
|
-
var DATABASE_ARGUMENT = `the database id (default: $SOFTR_DATABASE_ID, else the one in ${DB_CONFIG_FILE_NAME})`;
|
|
15424
|
-
var DIR_OPTION = `database directory, the one holding ${DB_CONFIG_FILE_NAME} (default: the current directory)`;
|
|
15425
15574
|
function renderDatabases(databases) {
|
|
15426
15575
|
if (!databases.length) {
|
|
15427
15576
|
return "The token reaches no database. Create one with: softr db create <name>";
|
|
15428
15577
|
}
|
|
15429
|
-
const table = new import_cli_table3.default(
|
|
15430
|
-
head: ["ID", "Name", "Workspace", "Tables"],
|
|
15431
|
-
colWidths: [38, 34, 38, 8],
|
|
15432
|
-
wordWrap: true,
|
|
15433
|
-
style: { head: [], border: [], "padding-left": 1, "padding-right": 1 }
|
|
15434
|
-
});
|
|
15578
|
+
const table = new import_cli_table3.default(plainTable(["ID", "Name", "Workspace", "Tables"], [38, 34, 38, 8]));
|
|
15435
15579
|
for (const database of databases) {
|
|
15436
15580
|
table.push([database.id, database.name, database.workspaceId, String(database.tablesCount)]);
|
|
15437
15581
|
}
|
|
@@ -15502,7 +15646,7 @@ Wrote ${path11.join(relativeDir(cwd, dir), DB_CONFIG_FILE_NAME)}.` : "";
|
|
|
15502
15646
|
);
|
|
15503
15647
|
}
|
|
15504
15648
|
);
|
|
15505
|
-
db2.command("update").description("Change a database's name or description").argument("[databaseId]",
|
|
15649
|
+
db2.command("update").description("Change a database's name or description").argument("[databaseId]", DATABASE_ID_HELP).option("--name <name>", "the new name").option("--description <text>", "the new description").option("--dir <path>", DATABASE_DIR_HELP).action(
|
|
15506
15650
|
async (databaseId, opts, command) => {
|
|
15507
15651
|
if (!opts.name && !opts.description) {
|
|
15508
15652
|
throw new CliError("Nothing to change: pass --name, --description or both.");
|
|
@@ -15521,7 +15665,7 @@ Wrote ${path11.join(relativeDir(cwd, dir), DB_CONFIG_FILE_NAME)}.` : "";
|
|
|
15521
15665
|
emit(options, `Updated database ${database.name} (${database.id}).`, { database });
|
|
15522
15666
|
}
|
|
15523
15667
|
);
|
|
15524
|
-
db2.command("delete").description("Delete a database; one that still has tables needs --force").argument("[databaseId]",
|
|
15668
|
+
db2.command("delete").description("Delete a database; one that still has tables needs --force").argument("[databaseId]", DATABASE_ID_HELP).option("--force", "also delete its tables and all their records").option("--dir <path>", DATABASE_DIR_HELP).action(async (databaseId, opts, command) => {
|
|
15525
15669
|
const options = globalOptions(command);
|
|
15526
15670
|
const target = await resolveDatabase(process.cwd(), databaseId, opts.dir);
|
|
15527
15671
|
const client = await authenticatedClient(resolveTarget());
|
|
@@ -15538,9 +15682,637 @@ ${path11.join(relativeDir(process.cwd(), target.dir), DB_CONFIG_FILE_NAME)} stil
|
|
|
15538
15682
|
});
|
|
15539
15683
|
}
|
|
15540
15684
|
|
|
15541
|
-
// src/commands/
|
|
15542
|
-
|
|
15685
|
+
// src/commands/db/records.ts
|
|
15686
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
15543
15687
|
import path12 from "node:path";
|
|
15688
|
+
|
|
15689
|
+
// src/commands/db/json-input.ts
|
|
15690
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
15691
|
+
async function readJsonArgument(value, option, hint) {
|
|
15692
|
+
let text = value;
|
|
15693
|
+
if (value === "-") {
|
|
15694
|
+
const chunks = [];
|
|
15695
|
+
for await (const chunk of process.stdin) {
|
|
15696
|
+
chunks.push(chunk);
|
|
15697
|
+
}
|
|
15698
|
+
text = Buffer.concat(chunks).toString("utf8");
|
|
15699
|
+
} else if (value.startsWith("@")) {
|
|
15700
|
+
text = await readFile8(value.slice(1), "utf8");
|
|
15701
|
+
}
|
|
15702
|
+
try {
|
|
15703
|
+
return JSON.parse(text);
|
|
15704
|
+
} catch {
|
|
15705
|
+
throw new CliError(`${option} is not valid JSON.`, hint ?? "Pass inline JSON, @<file> or - for stdin.");
|
|
15706
|
+
}
|
|
15707
|
+
}
|
|
15708
|
+
|
|
15709
|
+
// src/commands/db/schema.ts
|
|
15710
|
+
var import_cli_table32 = __toESM(require_cli_table3(), 1);
|
|
15711
|
+
var FIELD_REFERENCE_URL = "https://docs.softr.io/softr-api/softr-database-api/table-fields/add-table-field";
|
|
15712
|
+
var TABLE_ARGUMENT = "the table id or exact name";
|
|
15713
|
+
var FIELD_ARGUMENT = "the field id or exact name";
|
|
15714
|
+
function withDatabaseOptions(command) {
|
|
15715
|
+
return command.option("--database <id>", DATABASE_ID_HELP).option("--dir <path>", DATABASE_DIR_HELP);
|
|
15716
|
+
}
|
|
15717
|
+
async function schemaContext(opts) {
|
|
15718
|
+
const target = await resolveDatabase(process.cwd(), opts.database, opts.dir);
|
|
15719
|
+
const client = await authenticatedClient(resolveTarget());
|
|
15720
|
+
const cache = target.dir ? await readSchemaCache(target.dir) : void 0;
|
|
15721
|
+
return { client, databaseId: target.databaseId, dir: target.dir, cache };
|
|
15722
|
+
}
|
|
15723
|
+
async function currentTables(context, fresh) {
|
|
15724
|
+
if (!context.dir) {
|
|
15725
|
+
return listTables(context.client, context.databaseId);
|
|
15726
|
+
}
|
|
15727
|
+
if (!fresh && context.cache) {
|
|
15728
|
+
return context.cache.tables;
|
|
15729
|
+
}
|
|
15730
|
+
context.cache = await refreshSchemaCache(context.client, context.dir, context.databaseId);
|
|
15731
|
+
return context.cache.tables;
|
|
15732
|
+
}
|
|
15733
|
+
async function findTable(context, reference, fresh = false) {
|
|
15734
|
+
const table = byIdOrName(await currentTables(context, fresh), reference, "table") ?? (context.dir && !fresh ? byIdOrName(await currentTables(context, true), reference, "table") : void 0);
|
|
15735
|
+
if (!table) {
|
|
15736
|
+
throw new CliError(
|
|
15737
|
+
`Database ${context.databaseId} has no table with the id or name "${reference}".`,
|
|
15738
|
+
'"softr db tables list" shows its tables.'
|
|
15739
|
+
);
|
|
15740
|
+
}
|
|
15741
|
+
return table;
|
|
15742
|
+
}
|
|
15743
|
+
async function findFields(context, table, references, fresh = false) {
|
|
15744
|
+
const resolve = (current3) => {
|
|
15745
|
+
const fields2 = /* @__PURE__ */ new Map();
|
|
15746
|
+
for (const reference of references) {
|
|
15747
|
+
const field = byIdOrName(current3.fields, reference, "field");
|
|
15748
|
+
if (field) {
|
|
15749
|
+
fields2.set(reference, field);
|
|
15750
|
+
}
|
|
15751
|
+
}
|
|
15752
|
+
return fields2;
|
|
15753
|
+
};
|
|
15754
|
+
let current2 = table;
|
|
15755
|
+
let fields = resolve(current2);
|
|
15756
|
+
if (fields.size < new Set(references).size && context.dir && !fresh) {
|
|
15757
|
+
current2 = await findTable(context, table.id, true);
|
|
15758
|
+
fields = resolve(current2);
|
|
15759
|
+
}
|
|
15760
|
+
const missing = references.filter((reference) => !fields.has(reference));
|
|
15761
|
+
if (missing.length) {
|
|
15762
|
+
throw new CliError(
|
|
15763
|
+
`Table ${current2.name} has no field with the id or name ${missing.map((name) => `"${name}"`).join(", ")}.`,
|
|
15764
|
+
`"softr db tables get ${current2.id}" shows its fields.`
|
|
15765
|
+
);
|
|
15766
|
+
}
|
|
15767
|
+
return { table: current2, fields };
|
|
15768
|
+
}
|
|
15769
|
+
async function findField(context, tableReference, reference, fresh = false) {
|
|
15770
|
+
const found = await findFields(context, await findTable(context, tableReference, fresh), [reference], fresh);
|
|
15771
|
+
return { table: found.table, field: found.fields.get(reference) };
|
|
15772
|
+
}
|
|
15773
|
+
async function afterSchemaWrite(context) {
|
|
15774
|
+
if (context.dir) {
|
|
15775
|
+
context.cache = await refreshSchemaCache(context.client, context.dir, context.databaseId);
|
|
15776
|
+
}
|
|
15777
|
+
}
|
|
15778
|
+
function parseOptions(value) {
|
|
15779
|
+
return value === void 0 ? Promise.resolve(void 0) : readJsonArgument(value, "--options", `The options of each field type: ${FIELD_REFERENCE_URL}`);
|
|
15780
|
+
}
|
|
15781
|
+
function parseFieldSpec(spec) {
|
|
15782
|
+
const colon = spec.lastIndexOf(":");
|
|
15783
|
+
const name = colon > 0 ? spec.slice(0, colon).trim() : "";
|
|
15784
|
+
const type = colon > 0 ? spec.slice(colon + 1).trim().toUpperCase() : "";
|
|
15785
|
+
if (!name || !type) {
|
|
15786
|
+
throw new CliError(`--field "${spec}" must be <name>:<TYPE>, for example "Due date:DATE".`);
|
|
15787
|
+
}
|
|
15788
|
+
return { name, type };
|
|
15789
|
+
}
|
|
15790
|
+
function renderTables(tables) {
|
|
15791
|
+
if (!tables.length) {
|
|
15792
|
+
return "The database has no tables. Create one with: softr db tables create <name>";
|
|
15793
|
+
}
|
|
15794
|
+
const table = new import_cli_table32.default(plainTable(["ID", "Name", "Fields", "Primary field"], [18, 34, 8, 30]));
|
|
15795
|
+
for (const item of tables) {
|
|
15796
|
+
const primary = item.fields.find((field) => field.id === item.primaryFieldId);
|
|
15797
|
+
table.push([item.id, item.name, String(item.fields.length), primary?.name ?? item.primaryFieldId]);
|
|
15798
|
+
}
|
|
15799
|
+
return table.toString();
|
|
15800
|
+
}
|
|
15801
|
+
function flags(field, primaryFieldId) {
|
|
15802
|
+
return [
|
|
15803
|
+
field.id === primaryFieldId ? "primary" : "",
|
|
15804
|
+
field.required ? "required" : "",
|
|
15805
|
+
field.readonly ? "read-only" : "",
|
|
15806
|
+
field.allowMultipleEntries ? "multiple" : ""
|
|
15807
|
+
].filter(Boolean).join(", ");
|
|
15808
|
+
}
|
|
15809
|
+
function renderTable(item) {
|
|
15810
|
+
const fields = new import_cli_table32.default(plainTable(["ID", "Name", "Type", ""], [18, 30, 18, 30]));
|
|
15811
|
+
for (const field of item.fields) {
|
|
15812
|
+
fields.push([field.id, field.name, field.type, flags(field, item.primaryFieldId)]);
|
|
15813
|
+
}
|
|
15814
|
+
return [
|
|
15815
|
+
`${item.name} (${item.id})`,
|
|
15816
|
+
...item.description ? [` ${item.description}`] : [],
|
|
15817
|
+
` Default view: ${item.defaultViewId}`,
|
|
15818
|
+
fields.toString()
|
|
15819
|
+
].join("\n");
|
|
15820
|
+
}
|
|
15821
|
+
function renderField(table, field) {
|
|
15822
|
+
return [
|
|
15823
|
+
`${field.name} (${field.id}) in ${table.name}`,
|
|
15824
|
+
...field.description ? [` ${field.description}`] : [],
|
|
15825
|
+
` Type: ${field.type}`,
|
|
15826
|
+
...flags(field, table.primaryFieldId) ? [` Flags: ${flags(field, table.primaryFieldId)}`] : [],
|
|
15827
|
+
` Options: ${JSON.stringify(field.options ?? null)}`
|
|
15828
|
+
].join("\n");
|
|
15829
|
+
}
|
|
15830
|
+
function renderViews(views) {
|
|
15831
|
+
const table = new import_cli_table32.default(plainTable(["ID", "Name"], [18, 50]));
|
|
15832
|
+
for (const view of views) {
|
|
15833
|
+
table.push([view.id, view.name]);
|
|
15834
|
+
}
|
|
15835
|
+
return table.toString();
|
|
15836
|
+
}
|
|
15837
|
+
function registerTables(db2) {
|
|
15838
|
+
const tables = db2.command("tables").description("The tables of a database, with their fields");
|
|
15839
|
+
withDatabaseOptions(tables.command("list").description("List the tables of the database")).action(
|
|
15840
|
+
async (opts, command) => {
|
|
15841
|
+
const options = globalOptions(command);
|
|
15842
|
+
const context = await schemaContext(opts);
|
|
15843
|
+
const items = await currentTables(context, true);
|
|
15844
|
+
emit(options, renderTables(items), { databaseId: context.databaseId, tables: items });
|
|
15845
|
+
}
|
|
15846
|
+
);
|
|
15847
|
+
withDatabaseOptions(
|
|
15848
|
+
tables.command("get").description("Show a table with its fields").argument("<table>", TABLE_ARGUMENT)
|
|
15849
|
+
).action(async (reference, opts, command) => {
|
|
15850
|
+
const options = globalOptions(command);
|
|
15851
|
+
const context = await schemaContext(opts);
|
|
15852
|
+
const table = await findTable(context, reference, true);
|
|
15853
|
+
emit(options, renderTable(table), { table });
|
|
15854
|
+
});
|
|
15855
|
+
withDatabaseOptions(
|
|
15856
|
+
tables.command("create").description(
|
|
15857
|
+
"Create a table with at least one field; the first one names a record unless --primary-field says otherwise"
|
|
15858
|
+
).argument("<name>", "the table name").option("--description <text>", "what the table holds").option(
|
|
15859
|
+
"--field <name:TYPE>",
|
|
15860
|
+
`a field to create with it, repeatable (types and their options: ${FIELD_REFERENCE_URL}); add fields with options through "softr db fields add"`,
|
|
15861
|
+
(value, previous) => [...previous, value],
|
|
15862
|
+
[]
|
|
15863
|
+
).option("--primary-field <name>", "the field that names a record (default: the first field)")
|
|
15864
|
+
).action(
|
|
15865
|
+
async (name, opts, command) => {
|
|
15866
|
+
const options = globalOptions(command);
|
|
15867
|
+
if (!opts.field.length) {
|
|
15868
|
+
throw new CliError(
|
|
15869
|
+
'A table needs at least one field: pass --field <name>:<TYPE>, for example --field "Name:SINGLE_LINE_TEXT".',
|
|
15870
|
+
"Repeat --field for more; the first one names a record unless --primary-field names another."
|
|
15871
|
+
);
|
|
15872
|
+
}
|
|
15873
|
+
const fields = opts.field.map(parseFieldSpec);
|
|
15874
|
+
if (opts.primaryField && !fields.some((field) => field.name === opts.primaryField)) {
|
|
15875
|
+
throw new CliError(`--primary-field "${opts.primaryField}" is not one of the --field names.`);
|
|
15876
|
+
}
|
|
15877
|
+
const context = await schemaContext(opts);
|
|
15878
|
+
const table = await createTable(context.client, context.databaseId, {
|
|
15879
|
+
name,
|
|
15880
|
+
description: opts.description,
|
|
15881
|
+
primaryFieldName: opts.primaryField ?? fields[0].name,
|
|
15882
|
+
fields
|
|
15883
|
+
});
|
|
15884
|
+
await afterSchemaWrite(context);
|
|
15885
|
+
emit(options, `Created table ${table.name} (${table.id}) with ${table.fields.length} fields.`, { table });
|
|
15886
|
+
}
|
|
15887
|
+
);
|
|
15888
|
+
withDatabaseOptions(
|
|
15889
|
+
tables.command("update").description("Change a table's name or description").argument("<table>", TABLE_ARGUMENT).option("--name <name>", "the new name").option("--description <text>", "the new description")
|
|
15890
|
+
).action(
|
|
15891
|
+
async (reference, opts, command) => {
|
|
15892
|
+
if (!opts.name && opts.description === void 0) {
|
|
15893
|
+
throw new CliError("Nothing to change: pass --name, --description or both.");
|
|
15894
|
+
}
|
|
15895
|
+
const options = globalOptions(command);
|
|
15896
|
+
const context = await schemaContext(opts);
|
|
15897
|
+
const current2 = await findTable(context, reference, true);
|
|
15898
|
+
const table = await updateTable(context.client, context.databaseId, current2.id, {
|
|
15899
|
+
name: opts.name ?? current2.name,
|
|
15900
|
+
description: opts.description ?? current2.description
|
|
15901
|
+
});
|
|
15902
|
+
await afterSchemaWrite(context);
|
|
15903
|
+
emit(options, `Updated table ${table.name} (${table.id}).`, { table });
|
|
15904
|
+
}
|
|
15905
|
+
);
|
|
15906
|
+
withDatabaseOptions(
|
|
15907
|
+
tables.command("delete").description("Delete a table; one that still has records needs --force").argument("<table>", TABLE_ARGUMENT).option("--force", "also delete all its records")
|
|
15908
|
+
).action(async (reference, opts, command) => {
|
|
15909
|
+
const options = globalOptions(command);
|
|
15910
|
+
const context = await schemaContext(opts);
|
|
15911
|
+
const table = await findTable(context, reference, true);
|
|
15912
|
+
await deleteTable(context.client, context.databaseId, table.id, opts.force === true);
|
|
15913
|
+
await afterSchemaWrite(context);
|
|
15914
|
+
emit(options, `Deleted table ${table.name} (${table.id}).`, { deleted: table.id });
|
|
15915
|
+
});
|
|
15916
|
+
}
|
|
15917
|
+
function registerFields(db2) {
|
|
15918
|
+
const fields = db2.command("fields").description("The fields of a table");
|
|
15919
|
+
withDatabaseOptions(
|
|
15920
|
+
fields.command("get").description("Show a field with its options").argument("<table>", TABLE_ARGUMENT).argument("<field>", FIELD_ARGUMENT)
|
|
15921
|
+
).action(async (tableReference, reference, opts, command) => {
|
|
15922
|
+
const options = globalOptions(command);
|
|
15923
|
+
const context = await schemaContext(opts);
|
|
15924
|
+
const { table, field } = await findField(context, tableReference, reference, true);
|
|
15925
|
+
emit(options, renderField(table, field), { tableId: table.id, field });
|
|
15926
|
+
});
|
|
15927
|
+
withDatabaseOptions(
|
|
15928
|
+
fields.command("add").description("Add a field to a table").argument("<table>", TABLE_ARGUMENT).argument("<name>", "the field name").requiredOption("--type <TYPE>", "the field type, for example SINGLE_LINE_TEXT, NUMBER, SELECT, LINKED_RECORD").option("--options <json>", `the type's options as JSON, @<file> or - for stdin (${FIELD_REFERENCE_URL})`).option("--description <text>", "what the field holds").option("--multiple", "allow several values (SELECT, LINKED_RECORD, USER, ATTACHMENT)")
|
|
15929
|
+
).action(
|
|
15930
|
+
async (tableReference, name, opts, command) => {
|
|
15931
|
+
const options = globalOptions(command);
|
|
15932
|
+
const fieldOptions = await parseOptions(opts.options);
|
|
15933
|
+
const context = await schemaContext(opts);
|
|
15934
|
+
const table = await findTable(context, tableReference);
|
|
15935
|
+
const field = await addField(context.client, context.databaseId, table.id, {
|
|
15936
|
+
name,
|
|
15937
|
+
type: opts.type.toUpperCase(),
|
|
15938
|
+
description: opts.description,
|
|
15939
|
+
...fieldOptions === void 0 ? {} : { options: fieldOptions },
|
|
15940
|
+
allowMultipleEntries: opts.multiple === true
|
|
15941
|
+
});
|
|
15942
|
+
await afterSchemaWrite(context);
|
|
15943
|
+
emit(options, `Added field ${field.name} (${field.id}, ${field.type}) to ${table.name}.`, {
|
|
15944
|
+
tableId: table.id,
|
|
15945
|
+
field
|
|
15946
|
+
});
|
|
15947
|
+
}
|
|
15948
|
+
);
|
|
15949
|
+
withDatabaseOptions(
|
|
15950
|
+
fields.command("update").description("Change a field: what is not passed stays as it is").argument("<table>", TABLE_ARGUMENT).argument("<field>", FIELD_ARGUMENT).option("--name <name>", "the new name").option("--type <TYPE>", "the new type").option(
|
|
15951
|
+
"--options <json>",
|
|
15952
|
+
`the new options as JSON, @<file> or - for stdin, replacing the current ones (${FIELD_REFERENCE_URL})`
|
|
15953
|
+
).option("--description <text>", "the new description").option("--multiple", "allow several values").option("--no-multiple", "allow one value only")
|
|
15954
|
+
).action(
|
|
15955
|
+
async (tableReference, reference, opts, command) => {
|
|
15956
|
+
const fieldOptions = await parseOptions(opts.options);
|
|
15957
|
+
if (!opts.name && !opts.type && fieldOptions === void 0 && opts.description === void 0 && opts.multiple === void 0) {
|
|
15958
|
+
throw new CliError("Nothing to change: pass --name, --type, --options, --description or --[no-]multiple.");
|
|
15959
|
+
}
|
|
15960
|
+
const options = globalOptions(command);
|
|
15961
|
+
const context = await schemaContext(opts);
|
|
15962
|
+
const { table, field: current2 } = await findField(context, tableReference, reference, true);
|
|
15963
|
+
const field = await updateField(context.client, context.databaseId, table.id, current2.id, {
|
|
15964
|
+
name: opts.name ?? current2.name,
|
|
15965
|
+
type: opts.type?.toUpperCase() ?? current2.type,
|
|
15966
|
+
description: opts.description ?? current2.description,
|
|
15967
|
+
options: fieldOptions ?? current2.options,
|
|
15968
|
+
aiOptions: current2.aiOptions ?? null,
|
|
15969
|
+
defaultValue: current2.defaultValue ?? null,
|
|
15970
|
+
allowMultipleEntries: opts.multiple ?? current2.allowMultipleEntries
|
|
15971
|
+
});
|
|
15972
|
+
await afterSchemaWrite(context);
|
|
15973
|
+
emit(options, `Updated field ${field.name} (${field.id}, ${field.type}) in ${table.name}.`, {
|
|
15974
|
+
tableId: table.id,
|
|
15975
|
+
field
|
|
15976
|
+
});
|
|
15977
|
+
}
|
|
15978
|
+
);
|
|
15979
|
+
withDatabaseOptions(
|
|
15980
|
+
fields.command("delete").description("Delete a field and its values in every record").argument("<table>", TABLE_ARGUMENT).argument("<field>", FIELD_ARGUMENT)
|
|
15981
|
+
).action(async (tableReference, reference, opts, command) => {
|
|
15982
|
+
const options = globalOptions(command);
|
|
15983
|
+
const context = await schemaContext(opts);
|
|
15984
|
+
const { table, field } = await findField(context, tableReference, reference, true);
|
|
15985
|
+
await deleteField(context.client, context.databaseId, table.id, field.id);
|
|
15986
|
+
await afterSchemaWrite(context);
|
|
15987
|
+
emit(options, `Deleted field ${field.name} (${field.id}) from ${table.name}.`, {
|
|
15988
|
+
tableId: table.id,
|
|
15989
|
+
deleted: field.id
|
|
15990
|
+
});
|
|
15991
|
+
});
|
|
15992
|
+
}
|
|
15993
|
+
function registerViews(db2) {
|
|
15994
|
+
const views = db2.command("views").description("The views of a table");
|
|
15995
|
+
withDatabaseOptions(
|
|
15996
|
+
views.command("list").description("List the views of a table").argument("<table>", TABLE_ARGUMENT)
|
|
15997
|
+
).action(async (reference, opts, command) => {
|
|
15998
|
+
const options = globalOptions(command);
|
|
15999
|
+
const context = await schemaContext(opts);
|
|
16000
|
+
const table = await findTable(context, reference, true);
|
|
16001
|
+
const items = await listViews(context.client, context.databaseId, table.id);
|
|
16002
|
+
if (context.dir) {
|
|
16003
|
+
await writeViewsCache(context.dir, table.id, items);
|
|
16004
|
+
}
|
|
16005
|
+
emit(options, renderViews(items), { tableId: table.id, views: items });
|
|
16006
|
+
});
|
|
16007
|
+
}
|
|
16008
|
+
|
|
16009
|
+
// src/commands/db/records.ts
|
|
16010
|
+
var SEARCH_DOCS_URL = "https://docs.softr.io/softr-api/softr-database-api/records/search-records";
|
|
16011
|
+
var MAX_PAGE = 200;
|
|
16012
|
+
function withOutputOptions(command) {
|
|
16013
|
+
return command.option("--field-ids", "key record fields by field id instead of field name");
|
|
16014
|
+
}
|
|
16015
|
+
function withPagingOptions(command) {
|
|
16016
|
+
return command.option("--limit <n>", `records per page, 1 to ${MAX_PAGE} (default 20)`).option("--offset <n>", "records to skip (default 0)").option("--all", `every record, read in pages of ${MAX_PAGE}`);
|
|
16017
|
+
}
|
|
16018
|
+
function parseCount(value, option, max) {
|
|
16019
|
+
if (value === void 0) {
|
|
16020
|
+
return void 0;
|
|
16021
|
+
}
|
|
16022
|
+
const count = Number(value);
|
|
16023
|
+
if (!Number.isInteger(count) || count < 0 || max !== void 0 && (count < 1 || count > max)) {
|
|
16024
|
+
throw new CliError(`${option} must be a whole number${max ? ` from 1 to ${max}` : " of 0 or more"}.`);
|
|
16025
|
+
}
|
|
16026
|
+
return count;
|
|
16027
|
+
}
|
|
16028
|
+
function paging(opts) {
|
|
16029
|
+
if (opts.all && opts.limit !== void 0) {
|
|
16030
|
+
throw new CliError("Pass --all or --limit, not both.");
|
|
16031
|
+
}
|
|
16032
|
+
return {
|
|
16033
|
+
offset: parseCount(opts.offset, "--offset") ?? 0,
|
|
16034
|
+
limit: opts.all ? MAX_PAGE : parseCount(opts.limit, "--limit", MAX_PAGE) ?? 20,
|
|
16035
|
+
all: opts.all === true
|
|
16036
|
+
};
|
|
16037
|
+
}
|
|
16038
|
+
async function readPages(first, read) {
|
|
16039
|
+
const page = await read(first.offset, first.limit);
|
|
16040
|
+
if (!first.all) {
|
|
16041
|
+
return page;
|
|
16042
|
+
}
|
|
16043
|
+
const records = [...page.records];
|
|
16044
|
+
let offset2 = first.offset + page.records.length;
|
|
16045
|
+
while (page.records.length && offset2 < page.metadata.total) {
|
|
16046
|
+
const next = await read(offset2, first.limit);
|
|
16047
|
+
if (!next.records.length) {
|
|
16048
|
+
break;
|
|
16049
|
+
}
|
|
16050
|
+
records.push(...next.records);
|
|
16051
|
+
offset2 += next.records.length;
|
|
16052
|
+
}
|
|
16053
|
+
return { records, metadata: { offset: first.offset, limit: records.length, total: page.metadata.total } };
|
|
16054
|
+
}
|
|
16055
|
+
function asObject(value, option) {
|
|
16056
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
16057
|
+
throw new CliError(`${option} must be a JSON object.`);
|
|
16058
|
+
}
|
|
16059
|
+
return value;
|
|
16060
|
+
}
|
|
16061
|
+
async function fieldIdsFor(context, table, references) {
|
|
16062
|
+
const found = await findFields(context, table, references);
|
|
16063
|
+
return { table: found.table, ids: new Map([...found.fields].map(([reference, field]) => [reference, field.id])) };
|
|
16064
|
+
}
|
|
16065
|
+
async function mapFieldKeys(context, table, fields) {
|
|
16066
|
+
const { ids } = await fieldIdsFor(context, table, Object.keys(fields));
|
|
16067
|
+
return Object.fromEntries(Object.entries(fields).map(([key, value]) => [ids.get(key), value]));
|
|
16068
|
+
}
|
|
16069
|
+
function fieldReferences(condition, found) {
|
|
16070
|
+
if (Array.isArray(condition)) {
|
|
16071
|
+
condition.forEach((item) => fieldReferences(item, found));
|
|
16072
|
+
} else if (condition && typeof condition === "object") {
|
|
16073
|
+
for (const [key, value] of Object.entries(condition)) {
|
|
16074
|
+
if (key === "leftSide" && typeof value === "string") {
|
|
16075
|
+
found.add(value);
|
|
16076
|
+
} else {
|
|
16077
|
+
fieldReferences(value, found);
|
|
16078
|
+
}
|
|
16079
|
+
}
|
|
16080
|
+
}
|
|
16081
|
+
}
|
|
16082
|
+
function replaceFieldReferences(condition, ids) {
|
|
16083
|
+
if (Array.isArray(condition)) {
|
|
16084
|
+
return condition.map((item) => replaceFieldReferences(item, ids));
|
|
16085
|
+
}
|
|
16086
|
+
if (condition && typeof condition === "object") {
|
|
16087
|
+
return Object.fromEntries(
|
|
16088
|
+
Object.entries(condition).map(([key, value]) => [
|
|
16089
|
+
key,
|
|
16090
|
+
key === "leftSide" && typeof value === "string" ? ids.get(value) ?? value : replaceFieldReferences(value, ids)
|
|
16091
|
+
])
|
|
16092
|
+
);
|
|
16093
|
+
}
|
|
16094
|
+
return condition;
|
|
16095
|
+
}
|
|
16096
|
+
function parseSort(spec) {
|
|
16097
|
+
const colon = spec.lastIndexOf(":");
|
|
16098
|
+
const direction = colon > 0 ? spec.slice(colon + 1).trim().toUpperCase() : "";
|
|
16099
|
+
if (direction === "ASC" || direction === "DESC") {
|
|
16100
|
+
return { field: spec.slice(0, colon).trim(), sortType: direction };
|
|
16101
|
+
}
|
|
16102
|
+
return { field: spec.trim(), sortType: "ASC" };
|
|
16103
|
+
}
|
|
16104
|
+
async function findView(context, table, reference) {
|
|
16105
|
+
const fresh = async () => {
|
|
16106
|
+
const views = await listViews(context.client, context.databaseId, table.id);
|
|
16107
|
+
if (context.dir) {
|
|
16108
|
+
await writeViewsCache(context.dir, table.id, views);
|
|
16109
|
+
}
|
|
16110
|
+
return views;
|
|
16111
|
+
};
|
|
16112
|
+
const cached = context.dir ? (await readViewsCache(context.dir, table.id))?.views : void 0;
|
|
16113
|
+
const view = (cached ? byIdOrName(cached, reference, "view") : void 0) ?? byIdOrName(await fresh(), reference, "view");
|
|
16114
|
+
if (!view) {
|
|
16115
|
+
throw new CliError(
|
|
16116
|
+
`Table ${table.name} has no view with the id or name "${reference}".`,
|
|
16117
|
+
`"softr db views list ${table.id}" shows its views.`
|
|
16118
|
+
);
|
|
16119
|
+
}
|
|
16120
|
+
return view;
|
|
16121
|
+
}
|
|
16122
|
+
function withFieldNames(record, table) {
|
|
16123
|
+
const names2 = new Map(table.fields.map((field) => [field.id, field.name]));
|
|
16124
|
+
return {
|
|
16125
|
+
...record,
|
|
16126
|
+
fields: Object.fromEntries(Object.entries(record.fields).map(([key, value]) => [names2.get(key) ?? key, value]))
|
|
16127
|
+
};
|
|
16128
|
+
}
|
|
16129
|
+
function formatValue(value) {
|
|
16130
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
16131
|
+
}
|
|
16132
|
+
function renderRecord(record) {
|
|
16133
|
+
return [record.id, ...Object.entries(record.fields).map(([key, value]) => ` ${key}: ${formatValue(value)}`)].join(
|
|
16134
|
+
"\n"
|
|
16135
|
+
);
|
|
16136
|
+
}
|
|
16137
|
+
function renderPage(page) {
|
|
16138
|
+
if (!page.records.length) {
|
|
16139
|
+
return page.metadata.total ? `No records from offset ${page.metadata.offset}; ${page.metadata.total} in all.` : "No records.";
|
|
16140
|
+
}
|
|
16141
|
+
const shown = page.records.length;
|
|
16142
|
+
const end = page.metadata.offset + shown;
|
|
16143
|
+
const footer = end < page.metadata.total ? `${shown} of ${page.metadata.total} records; --offset ${end} for the next ones, or --all.` : `${shown} of ${page.metadata.total} records.`;
|
|
16144
|
+
return [...page.records.map(renderRecord), footer].join("\n\n");
|
|
16145
|
+
}
|
|
16146
|
+
function registerRecords(db2) {
|
|
16147
|
+
const records = db2.command("records").description("The records of a table; fields are keyed by name unless --field-ids");
|
|
16148
|
+
withOutputOptions(
|
|
16149
|
+
withPagingOptions(
|
|
16150
|
+
withDatabaseOptions(
|
|
16151
|
+
records.command("list").description(
|
|
16152
|
+
`List a table's records in the order and with the filter of a view, the table's default view unless --view; "records search" without --filter reads every record`
|
|
16153
|
+
).argument("<table>", TABLE_ARGUMENT).option("--view <view>", "the view id or exact name (default: the table's default view)")
|
|
16154
|
+
)
|
|
16155
|
+
)
|
|
16156
|
+
).action(
|
|
16157
|
+
async (reference, opts, command) => {
|
|
16158
|
+
const options = globalOptions(command);
|
|
16159
|
+
const pages = paging(opts);
|
|
16160
|
+
const context = await schemaContext(opts);
|
|
16161
|
+
const table = await findTable(context, reference);
|
|
16162
|
+
const viewId = opts.view ? (await findView(context, table, opts.view)).id : void 0;
|
|
16163
|
+
const page = await readPages(
|
|
16164
|
+
pages,
|
|
16165
|
+
(offset2, limit) => listRecords(context.client, context.databaseId, table.id, {
|
|
16166
|
+
viewId,
|
|
16167
|
+
offset: offset2,
|
|
16168
|
+
limit,
|
|
16169
|
+
fieldNames: !opts.fieldIds
|
|
16170
|
+
})
|
|
16171
|
+
);
|
|
16172
|
+
emit(options, renderPage(page), { tableId: table.id, ...page });
|
|
16173
|
+
}
|
|
16174
|
+
);
|
|
16175
|
+
withOutputOptions(
|
|
16176
|
+
withPagingOptions(
|
|
16177
|
+
withDatabaseOptions(
|
|
16178
|
+
records.command("search").description("Find records by a filter, sorted by fields").argument("<table>", TABLE_ARGUMENT).option(
|
|
16179
|
+
"--filter <json>",
|
|
16180
|
+
`the condition as JSON, @<file> or - for stdin; leftSide takes a field name or id (operators: ${SEARCH_DOCS_URL})`
|
|
16181
|
+
).option(
|
|
16182
|
+
"--sort <field[:asc|desc]>",
|
|
16183
|
+
"sort by a field, repeatable",
|
|
16184
|
+
(value, previous) => [...previous, value],
|
|
16185
|
+
[]
|
|
16186
|
+
)
|
|
16187
|
+
)
|
|
16188
|
+
)
|
|
16189
|
+
).action(
|
|
16190
|
+
async (reference, opts, command) => {
|
|
16191
|
+
const options = globalOptions(command);
|
|
16192
|
+
const pages = paging(opts);
|
|
16193
|
+
const parsed = opts.filter === void 0 ? void 0 : asObject(await readJsonArgument(opts.filter, "--filter"), "--filter");
|
|
16194
|
+
const condition = parsed && "condition" in parsed ? parsed["condition"] : parsed;
|
|
16195
|
+
const sorts = opts.sort.map(parseSort);
|
|
16196
|
+
const context = await schemaContext(opts);
|
|
16197
|
+
const references = new Set(sorts.map((sort) => sort.field));
|
|
16198
|
+
fieldReferences(condition, references);
|
|
16199
|
+
const { table, ids } = await fieldIdsFor(context, await findTable(context, reference), [...references]);
|
|
16200
|
+
const search = (offset2, limit) => ({
|
|
16201
|
+
paging: { offset: offset2, limit },
|
|
16202
|
+
...sorts.length ? { sorting: sorts.map((sort) => ({ sortingField: ids.get(sort.field), sortType: sort.sortType })) } : {},
|
|
16203
|
+
...condition === void 0 ? {} : { filter: { condition: replaceFieldReferences(condition, ids) } }
|
|
16204
|
+
});
|
|
16205
|
+
const page = await readPages(
|
|
16206
|
+
pages,
|
|
16207
|
+
(offset2, limit) => searchRecords(context.client, context.databaseId, table.id, search(offset2, limit), !opts.fieldIds)
|
|
16208
|
+
);
|
|
16209
|
+
emit(options, renderPage(page), { tableId: table.id, ...page });
|
|
16210
|
+
}
|
|
16211
|
+
);
|
|
16212
|
+
withOutputOptions(
|
|
16213
|
+
withDatabaseOptions(
|
|
16214
|
+
records.command("get").description("Show one record").argument("<table>", TABLE_ARGUMENT).argument("<recordId>", "the record id")
|
|
16215
|
+
)
|
|
16216
|
+
).action(async (reference, recordId, opts, command) => {
|
|
16217
|
+
const options = globalOptions(command);
|
|
16218
|
+
const context = await schemaContext(opts);
|
|
16219
|
+
const table = await findTable(context, reference);
|
|
16220
|
+
const record = await getRecord(context.client, context.databaseId, table.id, recordId, !opts.fieldIds);
|
|
16221
|
+
emit(options, renderRecord(record), { tableId: table.id, record });
|
|
16222
|
+
});
|
|
16223
|
+
withOutputOptions(
|
|
16224
|
+
withDatabaseOptions(
|
|
16225
|
+
records.command("create").description("Create a record").argument("<table>", TABLE_ARGUMENT).requiredOption(
|
|
16226
|
+
"--fields <json>",
|
|
16227
|
+
"the values as a JSON object keyed by field name or id, @<file> or - for stdin; {} creates an empty record"
|
|
16228
|
+
)
|
|
16229
|
+
)
|
|
16230
|
+
).action(async (reference, opts, command) => {
|
|
16231
|
+
const options = globalOptions(command);
|
|
16232
|
+
const fields = asObject(await readJsonArgument(opts.fields, "--fields"), "--fields");
|
|
16233
|
+
const context = await schemaContext(opts);
|
|
16234
|
+
const table = await findTable(context, reference);
|
|
16235
|
+
const record = await createRecord(
|
|
16236
|
+
context.client,
|
|
16237
|
+
context.databaseId,
|
|
16238
|
+
table.id,
|
|
16239
|
+
await mapFieldKeys(context, table, fields),
|
|
16240
|
+
!opts.fieldIds
|
|
16241
|
+
);
|
|
16242
|
+
emit(options, `Created record ${record.id} in ${table.name}.`, { tableId: table.id, record });
|
|
16243
|
+
});
|
|
16244
|
+
withOutputOptions(
|
|
16245
|
+
withDatabaseOptions(
|
|
16246
|
+
records.command("update").description("Change some fields of a record; the others keep their values").argument("<table>", TABLE_ARGUMENT).argument("<recordId>", "the record id").requiredOption(
|
|
16247
|
+
"--fields <json>",
|
|
16248
|
+
"the new values as a JSON object keyed by field name or id, @<file> or - for stdin; null clears a field"
|
|
16249
|
+
)
|
|
16250
|
+
)
|
|
16251
|
+
).action(
|
|
16252
|
+
async (reference, recordId, opts, command) => {
|
|
16253
|
+
const options = globalOptions(command);
|
|
16254
|
+
const fields = asObject(await readJsonArgument(opts.fields, "--fields"), "--fields");
|
|
16255
|
+
if (!Object.keys(fields).length) {
|
|
16256
|
+
throw new CliError("Nothing to change: --fields is an empty object.");
|
|
16257
|
+
}
|
|
16258
|
+
const context = await schemaContext(opts);
|
|
16259
|
+
const table = await findTable(context, reference);
|
|
16260
|
+
const record = await updateRecord(
|
|
16261
|
+
context.client,
|
|
16262
|
+
context.databaseId,
|
|
16263
|
+
table.id,
|
|
16264
|
+
recordId,
|
|
16265
|
+
await mapFieldKeys(context, table, fields),
|
|
16266
|
+
!opts.fieldIds
|
|
16267
|
+
);
|
|
16268
|
+
emit(options, `Updated record ${record.id} in ${table.name}.`, { tableId: table.id, record });
|
|
16269
|
+
}
|
|
16270
|
+
);
|
|
16271
|
+
withDatabaseOptions(
|
|
16272
|
+
records.command("delete").description("Delete a record").argument("<table>", TABLE_ARGUMENT).argument("<recordId>", "the record id")
|
|
16273
|
+
).action(async (reference, recordId, opts, command) => {
|
|
16274
|
+
const options = globalOptions(command);
|
|
16275
|
+
const context = await schemaContext(opts);
|
|
16276
|
+
const table = await findTable(context, reference, true);
|
|
16277
|
+
await deleteRecord(context.client, context.databaseId, table.id, recordId);
|
|
16278
|
+
emit(options, `Deleted record ${recordId} from ${table.name}.`, { tableId: table.id, deleted: recordId });
|
|
16279
|
+
});
|
|
16280
|
+
withOutputOptions(
|
|
16281
|
+
withDatabaseOptions(
|
|
16282
|
+
records.command("upload").description("Add a local file to a record's attachment field").argument("<table>", TABLE_ARGUMENT).argument("<recordId>", "the record id").argument("<field>", "the attachment field, by id or exact name").argument("<file>", "the file to upload").option("--name <fileName>", "the file name to store (default: the local file name)")
|
|
16283
|
+
)
|
|
16284
|
+
).action(
|
|
16285
|
+
async (reference, recordId, fieldReference, file, opts, command) => {
|
|
16286
|
+
const options = globalOptions(command);
|
|
16287
|
+
let content;
|
|
16288
|
+
try {
|
|
16289
|
+
content = await readFile9(file);
|
|
16290
|
+
} catch {
|
|
16291
|
+
throw new CliError(`Cannot read ${file}.`);
|
|
16292
|
+
}
|
|
16293
|
+
const context = await schemaContext(opts);
|
|
16294
|
+
const found = await fieldIdsFor(context, await findTable(context, reference), [fieldReference]);
|
|
16295
|
+
const fieldId = found.ids.get(fieldReference);
|
|
16296
|
+
const fieldType = found.table.fields.find((field) => field.id === fieldId)?.type;
|
|
16297
|
+
if (fieldType !== "ATTACHMENT") {
|
|
16298
|
+
throw new CliError(`Field "${fieldReference}" has the type ${fieldType}; upload needs an ATTACHMENT field.`);
|
|
16299
|
+
}
|
|
16300
|
+
const uploaded = await uploadAttachment(context.client, context.databaseId, found.table.id, recordId, fieldId, {
|
|
16301
|
+
name: opts.name ?? path12.basename(file),
|
|
16302
|
+
content
|
|
16303
|
+
});
|
|
16304
|
+
const record = opts.fieldIds ? uploaded : withFieldNames(uploaded, found.table);
|
|
16305
|
+
emit(options, `Uploaded ${opts.name ?? path12.basename(file)} to record ${record.id} in ${found.table.name}.`, {
|
|
16306
|
+
tableId: found.table.id,
|
|
16307
|
+
record
|
|
16308
|
+
});
|
|
16309
|
+
}
|
|
16310
|
+
);
|
|
16311
|
+
}
|
|
16312
|
+
|
|
16313
|
+
// src/commands/integrations.ts
|
|
16314
|
+
var import_cli_table33 = __toESM(require_cli_table3(), 1);
|
|
16315
|
+
import path13 from "node:path";
|
|
15544
16316
|
function toRow(integration) {
|
|
15545
16317
|
return {
|
|
15546
16318
|
id: integration.id,
|
|
@@ -15558,7 +16330,7 @@ function renderIntegrations(rows) {
|
|
|
15558
16330
|
if (!rows.length) {
|
|
15559
16331
|
return "No integrations connected in this workspace. Connect one in the studio (Workspace settings > Integrations).";
|
|
15560
16332
|
}
|
|
15561
|
-
const table = new
|
|
16333
|
+
const table = new import_cli_table33.default({
|
|
15562
16334
|
head: ["ID", "Name", "Type", "Account", "Auth"],
|
|
15563
16335
|
colWidths: [38, 34, 22, 30, 11],
|
|
15564
16336
|
wordWrap: true,
|
|
@@ -15572,7 +16344,7 @@ Use the ID as the integrationId input of a node (see "spec <TYPE>").`;
|
|
|
15572
16344
|
}
|
|
15573
16345
|
async function workflowDirOf(cwd, dir) {
|
|
15574
16346
|
if (dir) {
|
|
15575
|
-
return
|
|
16347
|
+
return path13.resolve(cwd, dir);
|
|
15576
16348
|
}
|
|
15577
16349
|
return await configExists(cwd) ? cwd : void 0;
|
|
15578
16350
|
}
|
|
@@ -15610,7 +16382,7 @@ ${renderIntegrations(rows)}`, {
|
|
|
15610
16382
|
}
|
|
15611
16383
|
|
|
15612
16384
|
// src/commands/list.ts
|
|
15613
|
-
var
|
|
16385
|
+
var import_cli_table34 = __toESM(require_cli_table3(), 1);
|
|
15614
16386
|
function toRow2(workflow, workspace) {
|
|
15615
16387
|
return {
|
|
15616
16388
|
id: workflow.id,
|
|
@@ -15652,7 +16424,7 @@ async function collectWorkflows(client, { workspaceId, applicationId } = {}) {
|
|
|
15652
16424
|
}
|
|
15653
16425
|
var TITLE_WIDTH = 34;
|
|
15654
16426
|
function workflowTable(rows) {
|
|
15655
|
-
const table = new
|
|
16427
|
+
const table = new import_cli_table34.default({
|
|
15656
16428
|
head: ["ID", "Title", "Triggers", "Status", "Version", "Draft"],
|
|
15657
16429
|
// Only the free-text title wraps; the other columns size to their content, so trigger types are never cut off.
|
|
15658
16430
|
colWidths: [null, TITLE_WIDTH, null, null, null, null],
|
|
@@ -15973,7 +16745,7 @@ ${identity.statements.map((s) => ` ${s.actions.join(", ")} on ${s.resources.joi
|
|
|
15973
16745
|
}
|
|
15974
16746
|
|
|
15975
16747
|
// src/commands/outputs.ts
|
|
15976
|
-
var
|
|
16748
|
+
var import_cli_table36 = __toESM(require_cli_table3(), 1);
|
|
15977
16749
|
|
|
15978
16750
|
// src/project/test-state.ts
|
|
15979
16751
|
function outdatedReferences(row) {
|
|
@@ -15986,28 +16758,28 @@ function renderIssues(issues) {
|
|
|
15986
16758
|
|
|
15987
16759
|
// src/project/variables.ts
|
|
15988
16760
|
var MAX_VARIABLES = 200;
|
|
15989
|
-
function appendKey(
|
|
15990
|
-
return /^[A-Za-z_]\w*$/.test(key) ? `${
|
|
16761
|
+
function appendKey(path16, key) {
|
|
16762
|
+
return /^[A-Za-z_]\w*$/.test(key) ? `${path16}.${key}` : `${path16}['${key.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}']`;
|
|
15991
16763
|
}
|
|
15992
16764
|
function isPrimitive2(value) {
|
|
15993
16765
|
return value !== void 0 && value !== null && typeof value !== "object";
|
|
15994
16766
|
}
|
|
15995
|
-
function walk(type, raw,
|
|
16767
|
+
function walk(type, raw, path16, token, out) {
|
|
15996
16768
|
if (out.length >= MAX_VARIABLES) {
|
|
15997
16769
|
return;
|
|
15998
16770
|
}
|
|
15999
|
-
out.push({ variable: token(
|
|
16771
|
+
out.push({ variable: token(path16), path: path16, type, ...isPrimitive2(raw) ? { example: raw } : {} });
|
|
16000
16772
|
if (type.kind === "object") {
|
|
16001
16773
|
for (const [key, field] of Object.entries(type.fields)) {
|
|
16002
16774
|
const rawField = raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw[key] : void 0;
|
|
16003
|
-
walk(field.type, rawField, appendKey(
|
|
16775
|
+
walk(field.type, rawField, appendKey(path16, key), token, out);
|
|
16004
16776
|
}
|
|
16005
16777
|
} else if (type.kind === "array") {
|
|
16006
|
-
walk(type.items, Array.isArray(raw) ? raw[0] : void 0, `${
|
|
16778
|
+
walk(type.items, Array.isArray(raw) ? raw[0] : void 0, `${path16}[*]`, token, out);
|
|
16007
16779
|
}
|
|
16008
16780
|
}
|
|
16009
16781
|
function collectVariables(nodeId, sample, metadata) {
|
|
16010
|
-
const token = (
|
|
16782
|
+
const token = (path16) => `{outputs.${nodeId}:::${path16}}`;
|
|
16011
16783
|
const variables = [];
|
|
16012
16784
|
if (sample !== void 0 && sample !== null) {
|
|
16013
16785
|
walk(typeOfJson(sample), sample, "$", token, variables);
|
|
@@ -16022,7 +16794,7 @@ function collectVariables(nodeId, sample, metadata) {
|
|
|
16022
16794
|
}
|
|
16023
16795
|
|
|
16024
16796
|
// src/commands/test.ts
|
|
16025
|
-
var
|
|
16797
|
+
var import_cli_table35 = __toESM(require_cli_table3(), 1);
|
|
16026
16798
|
var OUTPUTS_FILE = "outputs.json";
|
|
16027
16799
|
function fieldCount(row) {
|
|
16028
16800
|
const output = row.sampleOutput?.result?.output;
|
|
@@ -16123,7 +16895,7 @@ var LABEL = {
|
|
|
16123
16895
|
error: "ERROR"
|
|
16124
16896
|
};
|
|
16125
16897
|
function renderResults(results) {
|
|
16126
|
-
const table = new
|
|
16898
|
+
const table = new import_cli_table35.default({
|
|
16127
16899
|
head: ["Result", "Node", "Type", "Detail"],
|
|
16128
16900
|
colWidths: [9, 30, 24, 60],
|
|
16129
16901
|
wordWrap: true,
|
|
@@ -16239,7 +17011,7 @@ function sampleState(row) {
|
|
|
16239
17011
|
}
|
|
16240
17012
|
}
|
|
16241
17013
|
function renderVariables(nodeId, entries, unverified) {
|
|
16242
|
-
const table = new
|
|
17014
|
+
const table = new import_cli_table36.default({
|
|
16243
17015
|
head: ["Variable", "Type", "Example"],
|
|
16244
17016
|
colWidths: [64, 32, 44],
|
|
16245
17017
|
wordWrap: true,
|
|
@@ -16307,7 +17079,7 @@ function registerOutputs(program3) {
|
|
|
16307
17079
|
outdated: Object.keys(outdatedReferences(row))
|
|
16308
17080
|
};
|
|
16309
17081
|
});
|
|
16310
|
-
const table = new
|
|
17082
|
+
const table = new import_cli_table36.default({
|
|
16311
17083
|
head: ["Node", "Type", "Sample", "Fields"],
|
|
16312
17084
|
colWidths: [30, 24, 60, 8],
|
|
16313
17085
|
wordWrap: true,
|
|
@@ -16339,19 +17111,19 @@ function pathFromKeys(keys) {
|
|
|
16339
17111
|
const only = keys[0].trim();
|
|
16340
17112
|
return only.startsWith("$") ? only : `$${only.startsWith("[") ? "" : "."}${only}`;
|
|
16341
17113
|
}
|
|
16342
|
-
let
|
|
17114
|
+
let path16 = "$";
|
|
16343
17115
|
for (const key of keys) {
|
|
16344
17116
|
if (key === "*") {
|
|
16345
|
-
|
|
17117
|
+
path16 += "[*]";
|
|
16346
17118
|
} else if (/^\d+$/.test(key)) {
|
|
16347
|
-
|
|
17119
|
+
path16 += `[${key}]`;
|
|
16348
17120
|
} else if (/^[A-Za-z_]\w*$/.test(key)) {
|
|
16349
|
-
|
|
17121
|
+
path16 += `.${key}`;
|
|
16350
17122
|
} else {
|
|
16351
|
-
|
|
17123
|
+
path16 += `['${key.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}']`;
|
|
16352
17124
|
}
|
|
16353
17125
|
}
|
|
16354
|
-
return
|
|
17126
|
+
return path16;
|
|
16355
17127
|
}
|
|
16356
17128
|
function keysAt(type) {
|
|
16357
17129
|
switch (type.kind) {
|
|
@@ -16376,12 +17148,12 @@ function registerPlaceholder(program3) {
|
|
|
16376
17148
|
}
|
|
16377
17149
|
const rows = await readStateFile(dir, OUTPUTS_FILE) ?? [];
|
|
16378
17150
|
const outputs = indexOutputs(rows);
|
|
16379
|
-
const
|
|
16380
|
-
if (!parsePath(
|
|
16381
|
-
throw new CliError(`Cannot read the path "${
|
|
17151
|
+
const path16 = pathFromKeys(keys);
|
|
17152
|
+
if (!parsePath(path16)) {
|
|
17153
|
+
throw new CliError(`Cannot read the path "${path16}".`);
|
|
16382
17154
|
}
|
|
16383
17155
|
const isLoop = location.node.type === LOOP_TYPE;
|
|
16384
|
-
const token = isLoop ? `{loopActionGroup.${nodeId}:::loopVariables.items${
|
|
17156
|
+
const token = isLoop ? `{loopActionGroup.${nodeId}:::loopVariables.items${path16 === "$" ? "" : path16.slice(1)}}` : `{outputs.${nodeId}:::${path16}}`;
|
|
16385
17157
|
const [description] = describeInputData(
|
|
16386
17158
|
{ id: "probe", type: "CUSTOM_CODE", inputs: { inputData: { probe: token } } },
|
|
16387
17159
|
config,
|
|
@@ -16391,7 +17163,7 @@ function registerPlaceholder(program3) {
|
|
|
16391
17163
|
throw new CliError("Could not evaluate the token.");
|
|
16392
17164
|
}
|
|
16393
17165
|
if (description.type.kind === "unknown") {
|
|
16394
|
-
const segments = parsePath(
|
|
17166
|
+
const segments = parsePath(path16) ?? [];
|
|
16395
17167
|
let hint = description.note ?? "not found";
|
|
16396
17168
|
const row = outputs[nodeId];
|
|
16397
17169
|
if (row?.hasSample && segments.length) {
|
|
@@ -16417,7 +17189,7 @@ function registerPlaceholder(program3) {
|
|
|
16417
17189
|
emit(options, `${token}
|
|
16418
17190
|
type: ${type}${example3} (${status})`, {
|
|
16419
17191
|
token,
|
|
16420
|
-
path:
|
|
17192
|
+
path: path16,
|
|
16421
17193
|
type,
|
|
16422
17194
|
example: description.example ?? null,
|
|
16423
17195
|
verified: description.verified,
|
|
@@ -16427,10 +17199,10 @@ type: ${type}${example3} (${status})`, {
|
|
|
16427
17199
|
}
|
|
16428
17200
|
|
|
16429
17201
|
// src/commands/pull.ts
|
|
16430
|
-
import
|
|
17202
|
+
import path14 from "node:path";
|
|
16431
17203
|
async function targetDir(cwd, explicitDir, workflowId, title) {
|
|
16432
17204
|
if (explicitDir) {
|
|
16433
|
-
return
|
|
17205
|
+
return path14.resolve(cwd, explicitDir);
|
|
16434
17206
|
}
|
|
16435
17207
|
if (await configExists(cwd)) {
|
|
16436
17208
|
const existing = await readConfig(cwd);
|
|
@@ -16442,13 +17214,13 @@ async function targetDir(cwd, explicitDir, workflowId, title) {
|
|
|
16442
17214
|
}
|
|
16443
17215
|
return cwd;
|
|
16444
17216
|
}
|
|
16445
|
-
return
|
|
17217
|
+
return path14.join(cwd, slug(title));
|
|
16446
17218
|
}
|
|
16447
17219
|
function registerPull(program3) {
|
|
16448
17220
|
program3.command("pull").description("Download a workflow into softr-workflows.jsonc and one code file per custom code node").argument("[workflowId]", "the workflow id (last segment of its studio URL); omit to list what you can pull").option("--dir <path>", "target directory (default: this directory if it holds the workflow, else ./<title-slug>)").option("--force", "overwrite an existing softr-workflows.jsonc and its code files").action(async (workflowId, opts, command) => {
|
|
16449
17221
|
const options = globalOptions(command);
|
|
16450
17222
|
const cwd = process.cwd();
|
|
16451
|
-
const remembered = await readState(opts.dir ?
|
|
17223
|
+
const remembered = await readState(opts.dir ? path14.resolve(cwd, opts.dir) : cwd);
|
|
16452
17224
|
const target = resolveTarget(remembered);
|
|
16453
17225
|
const client = await authenticatedClient(target);
|
|
16454
17226
|
if (!workflowId) {
|
|
@@ -16461,7 +17233,7 @@ function registerPull(program3) {
|
|
|
16461
17233
|
const dir = await targetDir(cwd, opts.dir, workflowId, workflow.title);
|
|
16462
17234
|
if (await configExists(dir) && !opts.force) {
|
|
16463
17235
|
throw new CliError(
|
|
16464
|
-
`${
|
|
17236
|
+
`${path14.join(dir, CONFIG_FILE_NAME)} already exists.`,
|
|
16465
17237
|
"Pass --force to overwrite it and its code files."
|
|
16466
17238
|
);
|
|
16467
17239
|
}
|
|
@@ -16483,7 +17255,7 @@ Sample outputs not available, inputData types are unknown: ${error.message}`;
|
|
|
16483
17255
|
if (!outputsNote) {
|
|
16484
17256
|
outputsFile = await writeStateFile(dir, "outputs.json", rows);
|
|
16485
17257
|
}
|
|
16486
|
-
const files = [configFile2, ...codeFiles].map((file) =>
|
|
17258
|
+
const files = [configFile2, ...codeFiles].map((file) => path14.relative(cwd, file));
|
|
16487
17259
|
emitWithVersionNote(
|
|
16488
17260
|
options,
|
|
16489
17261
|
config,
|
|
@@ -16741,23 +17513,23 @@ function registerPin(program3) {
|
|
|
16741
17513
|
}
|
|
16742
17514
|
|
|
16743
17515
|
// src/commands/push.ts
|
|
16744
|
-
import
|
|
17516
|
+
import path15 from "node:path";
|
|
16745
17517
|
|
|
16746
17518
|
// src/project/placeholder-check.ts
|
|
16747
17519
|
var TOKEN = /\{(?:outputs|loopActionGroup)\.[^:{}]+:::[^{}]*\}/g;
|
|
16748
|
-
function* stringsIn(value,
|
|
17520
|
+
function* stringsIn(value, path16) {
|
|
16749
17521
|
if (typeof value === "string") {
|
|
16750
|
-
yield [
|
|
17522
|
+
yield [path16, value];
|
|
16751
17523
|
} else if (Array.isArray(value)) {
|
|
16752
17524
|
for (const [index, item] of value.entries()) {
|
|
16753
|
-
yield* stringsIn(item, `${
|
|
17525
|
+
yield* stringsIn(item, `${path16}[${index}]`);
|
|
16754
17526
|
}
|
|
16755
17527
|
} else if (value !== null && typeof value === "object") {
|
|
16756
17528
|
for (const [key, item] of Object.entries(value)) {
|
|
16757
17529
|
if (key === "actions" || key === "paths") {
|
|
16758
17530
|
continue;
|
|
16759
17531
|
}
|
|
16760
|
-
yield* stringsIn(item,
|
|
17532
|
+
yield* stringsIn(item, path16 ? `${path16}.${key}` : key);
|
|
16761
17533
|
}
|
|
16762
17534
|
}
|
|
16763
17535
|
}
|
|
@@ -16868,7 +17640,7 @@ ${unbacked.map(
|
|
|
16868
17640
|
draft: result.draft,
|
|
16869
17641
|
inlined,
|
|
16870
17642
|
studioUrl,
|
|
16871
|
-
dir:
|
|
17643
|
+
dir: path15.resolve(dir),
|
|
16872
17644
|
unbackedPlaceholders: unbacked
|
|
16873
17645
|
}
|
|
16874
17646
|
);
|
|
@@ -16876,10 +17648,10 @@ ${unbacked.map(
|
|
|
16876
17648
|
}
|
|
16877
17649
|
|
|
16878
17650
|
// src/commands/spec.ts
|
|
16879
|
-
var
|
|
17651
|
+
var import_cli_table37 = __toESM(require_cli_table3(), 1);
|
|
16880
17652
|
var TABLE_STYLE2 = { head: [], border: [], "padding-left": 1, "padding-right": 1 };
|
|
16881
17653
|
function renderList() {
|
|
16882
|
-
const table = new
|
|
17654
|
+
const table = new import_cli_table37.default({
|
|
16883
17655
|
head: ["Type", "Kind", "Label", "Summary"],
|
|
16884
17656
|
colWidths: [40, 9, 24, 70],
|
|
16885
17657
|
wordWrap: true,
|
|
@@ -16907,7 +17679,7 @@ function renderEntry(entry) {
|
|
|
16907
17679
|
const blocks = [`${entry.type} (${entry.kind}) \u2014 ${entry.label}`, entry.summary, `Docs: ${entry.docs}`];
|
|
16908
17680
|
const inputs = Object.entries(entry.inputs);
|
|
16909
17681
|
if (inputs.length) {
|
|
16910
|
-
const table = new
|
|
17682
|
+
const table = new import_cli_table37.default({
|
|
16911
17683
|
head: ["Input", "Type", "Required", "Description"],
|
|
16912
17684
|
colWidths: [20, 9, 10, 90],
|
|
16913
17685
|
wordWrap: true,
|
|
@@ -17157,14 +17929,14 @@ ${item.lines.map((line) => ` ${line}`).join("\n")}`
|
|
|
17157
17929
|
}
|
|
17158
17930
|
|
|
17159
17931
|
// src/commands/workspaces.ts
|
|
17160
|
-
var
|
|
17932
|
+
var import_cli_table38 = __toESM(require_cli_table3(), 1);
|
|
17161
17933
|
function registerWorkspaces(program3) {
|
|
17162
17934
|
program3.command("workspaces").description("The workspaces the stored token reaches, with your role and the scopes the token grants in each").action(async (_opts, command) => {
|
|
17163
17935
|
const options = globalOptions(command);
|
|
17164
17936
|
const target = resolveTarget();
|
|
17165
17937
|
const client = await authenticatedClient(target);
|
|
17166
17938
|
const workspaces = await listWorkspaces(client);
|
|
17167
|
-
const table = new
|
|
17939
|
+
const table = new import_cli_table38.default({
|
|
17168
17940
|
head: ["ID", "Name", "Role", "Default", "Scopes"],
|
|
17169
17941
|
colWidths: [38, 26, 10, 9, 34],
|
|
17170
17942
|
wordWrap: true,
|
|
@@ -17191,7 +17963,7 @@ Pass --workspace <id> to a command, or set SOFTR_WORKSPACE_ID, to work in one of
|
|
|
17191
17963
|
// package.json
|
|
17192
17964
|
var package_default = {
|
|
17193
17965
|
name: "@softr/cli",
|
|
17194
|
-
version: "0.1.
|
|
17966
|
+
version: "0.1.6-se21219.17",
|
|
17195
17967
|
description: "The Softr command line: build, test and publish Softr workflows from local files, manage Softr Databases; more Softr APIs to come",
|
|
17196
17968
|
keywords: [
|
|
17197
17969
|
"softr",
|
|
@@ -17219,7 +17991,7 @@ var package_default = {
|
|
|
17219
17991
|
format: "prettier --write .",
|
|
17220
17992
|
"format:check": "prettier --check .",
|
|
17221
17993
|
check: "npm run typecheck && npm run format:check && npm test && npm run build",
|
|
17222
|
-
"check:skill": "npx -y skills-ref@0.1.5 validate skills/softr-cli && npx -y skills-ref@0.1.5 validate skills/softr-workflows"
|
|
17994
|
+
"check:skill": "npx -y skills-ref@0.1.5 validate skills/softr-cli && npx -y skills-ref@0.1.5 validate skills/softr-workflows && npx -y skills-ref@0.1.5 validate skills/softr-db"
|
|
17223
17995
|
},
|
|
17224
17996
|
publishConfig: {
|
|
17225
17997
|
access: "public"
|
|
@@ -17264,4 +18036,8 @@ registerSpec(workflows);
|
|
|
17264
18036
|
registerSchema(workflows);
|
|
17265
18037
|
var db = program2.command("db").description("Manage Softr Databases: databases, their tables, fields and records");
|
|
17266
18038
|
registerDatabases(db);
|
|
18039
|
+
registerTables(db);
|
|
18040
|
+
registerFields(db);
|
|
18041
|
+
registerViews(db);
|
|
18042
|
+
registerRecords(db);
|
|
17267
18043
|
program2.parseAsync(process.argv).catch(reportError);
|