@softr/cli 0.1.4 → 0.1.5
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 +24 -9
- package/dist/cli.mjs +514 -111
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -222,26 +222,41 @@ schema refresh the cache too; the CLI rewrites it at any time, so never edit it.
|
|
|
222
222
|
```
|
|
223
223
|
crm/
|
|
224
224
|
softr-db.jsonc # { "databaseId": "…" }
|
|
225
|
-
.softr-db/schema.json # the cache
|
|
225
|
+
.softr-db/schema.json # the cache of the tables and fields
|
|
226
|
+
.softr-db/views/<tableId>.json # the views of a table, once views list read them
|
|
226
227
|
```
|
|
227
228
|
|
|
228
|
-
| Command
|
|
229
|
-
|
|
|
230
|
-
| `db list`
|
|
231
|
-
| `db get [<database>] [--dir <path>]`
|
|
232
|
-
| `db create <name> [--description <text>] [--workspace <id>] [--dir <path>]`
|
|
233
|
-
| `db update [<databaseId>] [--name <name>] [--description <text>] [--dir <path>]`
|
|
234
|
-
| `db delete [<databaseId>] [--force] [--dir <path>]`
|
|
229
|
+
| Command | What it does |
|
|
230
|
+
| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
231
|
+
| `db list` | The databases the token reaches, across all workspaces, with their workspace and number of tables. |
|
|
232
|
+
| `db get [<database>] [--dir <path>]` | One database with its tables, by id or exact name. Outside a database directory it creates `./<name-slug>/`; inside one it refreshes the cache, and a different database is an error. |
|
|
233
|
+
| `db create <name> [--description <text>] [--workspace <id>] [--dir <path>]` | Create an empty database and its directory. The workspace defaults to `SOFTR_WORKSPACE_ID`, else to your only or default workspace among those where the token grants `databases.schema:write`. |
|
|
234
|
+
| `db update [<databaseId>] [--name <name>] [--description <text>] [--dir <path>]` | Change the name, the description or both. |
|
|
235
|
+
| `db delete [<databaseId>] [--force] [--dir <path>]` | Delete a database. One that still has tables needs `--force`, which also deletes the tables and all their records. The directory keeps its `softr-db.jsonc`; the cache goes. |
|
|
236
|
+
| `db tables list` / `get <table>` | The tables of the database; one table with its fields (ids, types, primary/required/read-only). |
|
|
237
|
+
| `db tables create <name> [--field <name:TYPE>]... [--fields <json>] [--primary-field <name>]` | Create a table with at least one field: `--field` for types without options, `--fields` (a JSON array, `@<file>` or `-`) for any; the first one names a record. |
|
|
238
|
+
| `db tables update <table> [--name] [--description]` / `delete <table> [--force]` | Rename or describe a table; delete it (`--force` when it still has records). |
|
|
239
|
+
| `db fields get <table> <field>` | One field with its options. |
|
|
240
|
+
| `db fields add <table> <name> --type <TYPE> [--options <json>] [--multiple]` | Add a field. The types and their options: [field reference](https://docs.softr.io/softr-api/softr-database-api/table-fields/add-table-field). |
|
|
241
|
+
| `db fields update <table> <field> [--name] [--type] [--options <json>] [--[no-]multiple]` | Change a field; what is not passed stays as it is, `--options` replaces the options as a whole. |
|
|
242
|
+
| `db fields delete <table> <field>` | Delete a field and its values in every record. |
|
|
243
|
+
| `db views list <table>` | The views of a table (the API reads views only). |
|
|
244
|
+
|
|
245
|
+
Tables and fields take an id or an exact name; a name two items share is an error that lists their ids. The table,
|
|
246
|
+
field and view commands take the database from `--database <id>`, else `SOFTR_DATABASE_ID`, else the database
|
|
247
|
+
directory, and keep its cache current; a delete always resolves the name on the server, never from the cache.
|
|
235
248
|
|
|
236
249
|
## Agent skills
|
|
237
250
|
|
|
238
|
-
|
|
251
|
+
Three skills in the [Agent Skills](https://agentskills.io) format, published in
|
|
239
252
|
[softr-io/softr-io-skills](https://github.com/softr-io/softr-io-skills):
|
|
240
253
|
|
|
241
254
|
- [`softr-cli`](https://github.com/softr-io/softr-io-skills/tree/master/skills/softr-cli): install and update the CLI,
|
|
242
255
|
log in, the root commands and the environment variables. Every other Softr skill builds on it.
|
|
243
256
|
- [`softr-workflows`](https://github.com/softr-io/softr-io-skills/tree/master/skills/softr-workflows): the
|
|
244
257
|
`softr workflows` scope, with the code-file rules in its `references/custom-code.md`.
|
|
258
|
+
- [`softr-db`](https://github.com/softr-io/softr-io-skills/tree/master/skills/softr-db): the `softr db` scope, the
|
|
259
|
+
database directory and the schema commands.
|
|
245
260
|
|
|
246
261
|
Install them as a plugin in Claude Code, which keeps them updated, or with `npx skills add softr-io/softr-io-skills`
|
|
247
262
|
in every other agent. The exact steps are on [docs.softr.io/softr-cli](https://docs.softr.io/softr-cli).
|
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;
|
|
@@ -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
|
}
|
|
@@ -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(), () => {
|
|
@@ -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
|
/**
|
|
@@ -6177,6 +6177,9 @@ function globalOptions(command) {
|
|
|
6177
6177
|
function emit(options, human, data2) {
|
|
6178
6178
|
process.stdout.write(options.json ? JSON.stringify(data2, null, 2) + "\n" : human + "\n");
|
|
6179
6179
|
}
|
|
6180
|
+
function plainTable(head, colWidths) {
|
|
6181
|
+
return { head, colWidths, wordWrap: true, style: { head: [], border: [], "padding-left": 1, "padding-right": 1 } };
|
|
6182
|
+
}
|
|
6180
6183
|
function reportError(error) {
|
|
6181
6184
|
if (error instanceof CliError || error instanceof SoftrApiError) {
|
|
6182
6185
|
process.stderr.write(`Error: ${error.message}
|
|
@@ -7636,8 +7639,8 @@ function parseJsoncFile(file, text) {
|
|
|
7636
7639
|
async function listSubdirsWith(cwd, holds) {
|
|
7637
7640
|
const entries = await readdir(cwd, { withFileTypes: true });
|
|
7638
7641
|
const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => path2.join(cwd, entry.name));
|
|
7639
|
-
const
|
|
7640
|
-
return dirs.filter((_, index) =>
|
|
7642
|
+
const flags2 = await Promise.all(dirs.map((dir) => holds(dir)));
|
|
7643
|
+
return dirs.filter((_, index) => flags2[index]);
|
|
7641
7644
|
}
|
|
7642
7645
|
async function readConfig(dir) {
|
|
7643
7646
|
const file = configPath(dir);
|
|
@@ -8284,12 +8287,12 @@ prototypeAccessors.inAsync.get = function() {
|
|
|
8284
8287
|
prototypeAccessors.canAwait.get = function() {
|
|
8285
8288
|
for (var i2 = this.scopeStack.length - 1; i2 >= 0; i2--) {
|
|
8286
8289
|
var ref2 = this.scopeStack[i2];
|
|
8287
|
-
var
|
|
8288
|
-
if (
|
|
8290
|
+
var flags2 = ref2.flags;
|
|
8291
|
+
if (flags2 & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT)) {
|
|
8289
8292
|
return false;
|
|
8290
8293
|
}
|
|
8291
|
-
if (
|
|
8292
|
-
return (
|
|
8294
|
+
if (flags2 & SCOPE_FUNCTION) {
|
|
8295
|
+
return (flags2 & SCOPE_ASYNC) > 0;
|
|
8293
8296
|
}
|
|
8294
8297
|
}
|
|
8295
8298
|
return this.inModule && this.options.ecmaVersion >= 13 || this.options.allowAwaitOutsideFunction;
|
|
@@ -8305,8 +8308,8 @@ prototypeAccessors.allowReturn.get = function() {
|
|
|
8305
8308
|
};
|
|
8306
8309
|
prototypeAccessors.allowSuper.get = function() {
|
|
8307
8310
|
var ref2 = this.currentThisScope();
|
|
8308
|
-
var
|
|
8309
|
-
return (
|
|
8311
|
+
var flags2 = ref2.flags;
|
|
8312
|
+
return (flags2 & SCOPE_SUPER) > 0 || this.options.allowSuperOutsideMethod;
|
|
8310
8313
|
};
|
|
8311
8314
|
prototypeAccessors.allowDirectSuper.get = function() {
|
|
8312
8315
|
return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0;
|
|
@@ -8317,8 +8320,8 @@ prototypeAccessors.treatFunctionsAsVar.get = function() {
|
|
|
8317
8320
|
prototypeAccessors.allowNewDotTarget.get = function() {
|
|
8318
8321
|
for (var i2 = this.scopeStack.length - 1; i2 >= 0; i2--) {
|
|
8319
8322
|
var ref2 = this.scopeStack[i2];
|
|
8320
|
-
var
|
|
8321
|
-
if (
|
|
8323
|
+
var flags2 = ref2.flags;
|
|
8324
|
+
if (flags2 & (SCOPE_CLASS_STATIC_BLOCK | SCOPE_CLASS_FIELD_INIT) || flags2 & SCOPE_FUNCTION && !(flags2 & SCOPE_ARROW)) {
|
|
8322
8325
|
return true;
|
|
8323
8326
|
}
|
|
8324
8327
|
}
|
|
@@ -8326,11 +8329,11 @@ prototypeAccessors.allowNewDotTarget.get = function() {
|
|
|
8326
8329
|
};
|
|
8327
8330
|
prototypeAccessors.allowUsing.get = function() {
|
|
8328
8331
|
var ref2 = this.currentScope();
|
|
8329
|
-
var
|
|
8330
|
-
if (
|
|
8332
|
+
var flags2 = ref2.flags;
|
|
8333
|
+
if (flags2 & SCOPE_SWITCH) {
|
|
8331
8334
|
return false;
|
|
8332
8335
|
}
|
|
8333
|
-
if (!this.inModule &&
|
|
8336
|
+
if (!this.inModule && flags2 & SCOPE_TOP) {
|
|
8334
8337
|
return false;
|
|
8335
8338
|
}
|
|
8336
8339
|
return true;
|
|
@@ -11111,14 +11114,14 @@ pp$4.curPosition = function() {
|
|
|
11111
11114
|
}
|
|
11112
11115
|
};
|
|
11113
11116
|
var pp$3 = Parser.prototype;
|
|
11114
|
-
var Scope = function Scope2(
|
|
11115
|
-
this.flags =
|
|
11117
|
+
var Scope = function Scope2(flags2) {
|
|
11118
|
+
this.flags = flags2;
|
|
11116
11119
|
this.var = [];
|
|
11117
11120
|
this.lexical = [];
|
|
11118
11121
|
this.functions = [];
|
|
11119
11122
|
};
|
|
11120
|
-
pp$3.enterScope = function(
|
|
11121
|
-
this.scopeStack.push(new Scope(
|
|
11123
|
+
pp$3.enterScope = function(flags2) {
|
|
11124
|
+
this.scopeStack.push(new Scope(flags2));
|
|
11122
11125
|
};
|
|
11123
11126
|
pp$3.exitScope = function() {
|
|
11124
11127
|
this.scopeStack.pop();
|
|
@@ -11334,12 +11337,12 @@ var RegExpValidationState = function RegExpValidationState2(parser) {
|
|
|
11334
11337
|
this.backReferenceNames = [];
|
|
11335
11338
|
this.branchID = null;
|
|
11336
11339
|
};
|
|
11337
|
-
RegExpValidationState.prototype.reset = function reset(start, pattern,
|
|
11338
|
-
var unicodeSets =
|
|
11339
|
-
var unicode =
|
|
11340
|
+
RegExpValidationState.prototype.reset = function reset(start, pattern, flags2) {
|
|
11341
|
+
var unicodeSets = flags2.indexOf("v") !== -1;
|
|
11342
|
+
var unicode = flags2.indexOf("u") !== -1;
|
|
11340
11343
|
this.start = start | 0;
|
|
11341
11344
|
this.source = pattern + "";
|
|
11342
|
-
this.flags =
|
|
11345
|
+
this.flags = flags2;
|
|
11343
11346
|
if (unicodeSets && this.parser.options.ecmaVersion >= 15) {
|
|
11344
11347
|
this.switchU = true;
|
|
11345
11348
|
this.switchV = true;
|
|
@@ -11416,15 +11419,15 @@ RegExpValidationState.prototype.eatChars = function eatChars(chs, forceU) {
|
|
|
11416
11419
|
};
|
|
11417
11420
|
pp$1.validateRegExpFlags = function(state) {
|
|
11418
11421
|
var validFlags = state.validFlags;
|
|
11419
|
-
var
|
|
11422
|
+
var flags2 = state.flags;
|
|
11420
11423
|
var u = false;
|
|
11421
11424
|
var v = false;
|
|
11422
|
-
for (var i2 = 0; i2 <
|
|
11423
|
-
var flag =
|
|
11425
|
+
for (var i2 = 0; i2 < flags2.length; i2++) {
|
|
11426
|
+
var flag = flags2.charAt(i2);
|
|
11424
11427
|
if (validFlags.indexOf(flag) === -1) {
|
|
11425
11428
|
this.raise(state.start, "Invalid regular expression flag");
|
|
11426
11429
|
}
|
|
11427
|
-
if (
|
|
11430
|
+
if (flags2.indexOf(flag, i2 + 1) > -1) {
|
|
11428
11431
|
this.raise(state.start, "Duplicate regular expression flag");
|
|
11429
11432
|
}
|
|
11430
11433
|
if (flag === "u") {
|
|
@@ -13036,20 +13039,20 @@ pp.readRegexp = function() {
|
|
|
13036
13039
|
var pattern = this.input.slice(start, this.pos);
|
|
13037
13040
|
++this.pos;
|
|
13038
13041
|
var flagsStart = this.pos;
|
|
13039
|
-
var
|
|
13042
|
+
var flags2 = this.readWord1();
|
|
13040
13043
|
if (this.containsEsc) {
|
|
13041
13044
|
this.unexpected(flagsStart);
|
|
13042
13045
|
}
|
|
13043
13046
|
var state = this.regexpState || (this.regexpState = new RegExpValidationState(this));
|
|
13044
|
-
state.reset(start, pattern,
|
|
13047
|
+
state.reset(start, pattern, flags2);
|
|
13045
13048
|
this.validateRegExpFlags(state);
|
|
13046
13049
|
this.validateRegExpPattern(state);
|
|
13047
13050
|
var value = null;
|
|
13048
13051
|
try {
|
|
13049
|
-
value = new RegExp(pattern,
|
|
13052
|
+
value = new RegExp(pattern, flags2);
|
|
13050
13053
|
} catch (e) {
|
|
13051
13054
|
}
|
|
13052
|
-
return this.finishToken(types$1.regexp, { pattern, flags, value });
|
|
13055
|
+
return this.finishToken(types$1.regexp, { pattern, flags: flags2, value });
|
|
13053
13056
|
};
|
|
13054
13057
|
pp.readInt = function(radix, len, maybeLegacyOctalNumericLiteral) {
|
|
13055
13058
|
var allowSeparators = this.options.ecmaVersion >= 12 && len === void 0;
|
|
@@ -14575,6 +14578,36 @@ async function deleteDatabase(client, databaseId, force) {
|
|
|
14575
14578
|
async function listTables(client, databaseId) {
|
|
14576
14579
|
return (await tablesRequest(client, "GET", `${DATABASES}/${encodeURIComponent(databaseId)}/tables`)).data;
|
|
14577
14580
|
}
|
|
14581
|
+
function tablePath(databaseId, tableId) {
|
|
14582
|
+
const tables = `${DATABASES}/${encodeURIComponent(databaseId)}/tables`;
|
|
14583
|
+
return tableId ? `${tables}/${encodeURIComponent(tableId)}` : tables;
|
|
14584
|
+
}
|
|
14585
|
+
async function createTable(client, databaseId, table) {
|
|
14586
|
+
return (await tablesRequest(client, "POST", tablePath(databaseId), table)).data;
|
|
14587
|
+
}
|
|
14588
|
+
async function updateTable(client, databaseId, tableId, table) {
|
|
14589
|
+
return (await tablesRequest(client, "PUT", tablePath(databaseId, tableId), table)).data;
|
|
14590
|
+
}
|
|
14591
|
+
async function deleteTable(client, databaseId, tableId, force) {
|
|
14592
|
+
await tablesRequestVoid(client, "DELETE", `${tablePath(databaseId, tableId)}${force ? "?force=true" : ""}`);
|
|
14593
|
+
}
|
|
14594
|
+
async function addField(client, databaseId, tableId, field) {
|
|
14595
|
+
return (await tablesRequest(client, "POST", `${tablePath(databaseId, tableId)}/fields`, field)).data;
|
|
14596
|
+
}
|
|
14597
|
+
async function updateField(client, databaseId, tableId, fieldId, field) {
|
|
14598
|
+
return (await tablesRequest(
|
|
14599
|
+
client,
|
|
14600
|
+
"PUT",
|
|
14601
|
+
`${tablePath(databaseId, tableId)}/fields/${encodeURIComponent(fieldId)}`,
|
|
14602
|
+
field
|
|
14603
|
+
)).data;
|
|
14604
|
+
}
|
|
14605
|
+
async function deleteField(client, databaseId, tableId, fieldId) {
|
|
14606
|
+
await tablesRequestVoid(client, "DELETE", `${tablePath(databaseId, tableId)}/fields/${encodeURIComponent(fieldId)}`);
|
|
14607
|
+
}
|
|
14608
|
+
async function listViews(client, databaseId, tableId) {
|
|
14609
|
+
return (await tablesRequest(client, "GET", `${tablePath(databaseId, tableId)}/views`)).data;
|
|
14610
|
+
}
|
|
14578
14611
|
|
|
14579
14612
|
// src/config/credentials.ts
|
|
14580
14613
|
import { chmod, mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
@@ -14791,8 +14824,26 @@ async function authenticatedClient(target) {
|
|
|
14791
14824
|
}
|
|
14792
14825
|
|
|
14793
14826
|
// src/project/db-dir.ts
|
|
14794
|
-
import { mkdir as mkdir5, readFile as readFile6, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
14827
|
+
import { mkdir as mkdir5, readdir as readdir2, readFile as readFile6, rm, writeFile as writeFile6 } from "node:fs/promises";
|
|
14795
14828
|
import path8 from "node:path";
|
|
14829
|
+
|
|
14830
|
+
// src/project/lookup.ts
|
|
14831
|
+
function byIdOrName(items, reference, kind, describe2 = (item) => item.id) {
|
|
14832
|
+
const byId = items.find((item) => item.id === reference);
|
|
14833
|
+
if (byId) {
|
|
14834
|
+
return byId;
|
|
14835
|
+
}
|
|
14836
|
+
const byName = items.filter((item) => item.name === reference);
|
|
14837
|
+
if (byName.length > 1) {
|
|
14838
|
+
throw new CliError(
|
|
14839
|
+
`Several ${kind}s are named "${reference}".`,
|
|
14840
|
+
`Pass the id of one: ${byName.map(describe2).join(", ")}`
|
|
14841
|
+
);
|
|
14842
|
+
}
|
|
14843
|
+
return byName[0];
|
|
14844
|
+
}
|
|
14845
|
+
|
|
14846
|
+
// src/project/db-dir.ts
|
|
14796
14847
|
var DB_CONFIG_FILE_NAME = "softr-db.jsonc";
|
|
14797
14848
|
var DB_CACHE_DIR_NAME = ".softr-db";
|
|
14798
14849
|
var DATABASE_ID_ENV_VAR = "SOFTR_DATABASE_ID";
|
|
@@ -14841,8 +14892,31 @@ async function writeSchemaCache(dir, database, tables) {
|
|
|
14841
14892
|
const cache = { database, tables, refreshedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14842
14893
|
await mkdir5(path8.dirname(cacheFile(dir)), { recursive: true });
|
|
14843
14894
|
await writeFile6(cacheFile(dir), JSON.stringify(cache, null, 2) + "\n");
|
|
14895
|
+
await pruneViewsCache(dir, new Set(tables.map((table) => table.id)));
|
|
14844
14896
|
return cache;
|
|
14845
14897
|
}
|
|
14898
|
+
function viewsDir(dir) {
|
|
14899
|
+
return path8.join(dir, DB_CACHE_DIR_NAME, "views");
|
|
14900
|
+
}
|
|
14901
|
+
async function writeViewsCache(dir, tableId, views) {
|
|
14902
|
+
const value = { tableId, views, refreshedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14903
|
+
await mkdir5(viewsDir(dir), { recursive: true });
|
|
14904
|
+
await writeFile6(path8.join(viewsDir(dir), `${tableId}.json`), JSON.stringify(value, null, 2) + "\n");
|
|
14905
|
+
}
|
|
14906
|
+
async function pruneViewsCache(dir, tableIds) {
|
|
14907
|
+
let names;
|
|
14908
|
+
try {
|
|
14909
|
+
names = await readdir2(viewsDir(dir));
|
|
14910
|
+
} catch (error) {
|
|
14911
|
+
if (error.code === "ENOENT") {
|
|
14912
|
+
return;
|
|
14913
|
+
}
|
|
14914
|
+
throw error;
|
|
14915
|
+
}
|
|
14916
|
+
await Promise.all(
|
|
14917
|
+
names.filter((name) => name.endsWith(".json") && !tableIds.has(name.slice(0, -".json".length))).map((name) => rm(path8.join(viewsDir(dir), name), { force: true }))
|
|
14918
|
+
);
|
|
14919
|
+
}
|
|
14846
14920
|
async function refreshSchemaCache(client, dir, databaseId) {
|
|
14847
14921
|
const [database, tables] = await Promise.all([getDatabase(client, databaseId), listTables(client, databaseId)]);
|
|
14848
14922
|
return writeSchemaCache(dir, database, tables);
|
|
@@ -14903,25 +14977,19 @@ async function databaseDirFor(cwd, explicitDir, databaseId, dirName) {
|
|
|
14903
14977
|
return { dir: sibling2, existing: false };
|
|
14904
14978
|
}
|
|
14905
14979
|
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]) {
|
|
14980
|
+
const database = byIdOrName(
|
|
14981
|
+
await listDatabases(client),
|
|
14982
|
+
reference,
|
|
14983
|
+
"database",
|
|
14984
|
+
(item) => `${item.id} (workspace ${item.workspaceId})`
|
|
14985
|
+
);
|
|
14986
|
+
if (!database) {
|
|
14919
14987
|
throw new CliError(
|
|
14920
14988
|
`The token reaches no database with the id or name "${reference}".`,
|
|
14921
14989
|
'"softr db list" shows the ones it reaches.'
|
|
14922
14990
|
);
|
|
14923
14991
|
}
|
|
14924
|
-
return
|
|
14992
|
+
return database;
|
|
14925
14993
|
}
|
|
14926
14994
|
async function bindDatabaseDir(client, cwd, reference, explicitDir) {
|
|
14927
14995
|
const here = path8.resolve(cwd, explicitDir ?? ".");
|
|
@@ -14944,6 +15012,10 @@ async function bindDatabaseDir(client, cwd, reference, explicitDir) {
|
|
|
14944
15012
|
return { databaseId: database.id, dir, wrote: !existing };
|
|
14945
15013
|
}
|
|
14946
15014
|
|
|
15015
|
+
// src/commands/db/help.ts
|
|
15016
|
+
var DATABASE_ID_HELP = `the database id (default: $SOFTR_DATABASE_ID, else the one in ${DB_CONFIG_FILE_NAME})`;
|
|
15017
|
+
var DATABASE_DIR_HELP = `database directory, the one holding ${DB_CONFIG_FILE_NAME} (default: the current directory)`;
|
|
15018
|
+
|
|
14947
15019
|
// src/api/studio.ts
|
|
14948
15020
|
async function resolveTokenOwner(client) {
|
|
14949
15021
|
try {
|
|
@@ -15420,18 +15492,11 @@ Next: softr workflows add <TYPE> --dir ${path10.relative(cwd, dir) || "."} (see
|
|
|
15420
15492
|
}
|
|
15421
15493
|
|
|
15422
15494
|
// 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
15495
|
function renderDatabases(databases) {
|
|
15426
15496
|
if (!databases.length) {
|
|
15427
15497
|
return "The token reaches no database. Create one with: softr db create <name>";
|
|
15428
15498
|
}
|
|
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
|
-
});
|
|
15499
|
+
const table = new import_cli_table3.default(plainTable(["ID", "Name", "Workspace", "Tables"], [38, 34, 38, 8]));
|
|
15435
15500
|
for (const database of databases) {
|
|
15436
15501
|
table.push([database.id, database.name, database.workspaceId, String(database.tablesCount)]);
|
|
15437
15502
|
}
|
|
@@ -15502,7 +15567,7 @@ Wrote ${path11.join(relativeDir(cwd, dir), DB_CONFIG_FILE_NAME)}.` : "";
|
|
|
15502
15567
|
);
|
|
15503
15568
|
}
|
|
15504
15569
|
);
|
|
15505
|
-
db2.command("update").description("Change a database's name or description").argument("[databaseId]",
|
|
15570
|
+
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
15571
|
async (databaseId, opts, command) => {
|
|
15507
15572
|
if (!opts.name && !opts.description) {
|
|
15508
15573
|
throw new CliError("Nothing to change: pass --name, --description or both.");
|
|
@@ -15521,7 +15586,7 @@ Wrote ${path11.join(relativeDir(cwd, dir), DB_CONFIG_FILE_NAME)}.` : "";
|
|
|
15521
15586
|
emit(options, `Updated database ${database.name} (${database.id}).`, { database });
|
|
15522
15587
|
}
|
|
15523
15588
|
);
|
|
15524
|
-
db2.command("delete").description("Delete a database; one that still has tables needs --force").argument("[databaseId]",
|
|
15589
|
+
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
15590
|
const options = globalOptions(command);
|
|
15526
15591
|
const target = await resolveDatabase(process.cwd(), databaseId, opts.dir);
|
|
15527
15592
|
const client = await authenticatedClient(resolveTarget());
|
|
@@ -15538,8 +15603,343 @@ ${path11.join(relativeDir(process.cwd(), target.dir), DB_CONFIG_FILE_NAME)} stil
|
|
|
15538
15603
|
});
|
|
15539
15604
|
}
|
|
15540
15605
|
|
|
15541
|
-
// src/commands/
|
|
15606
|
+
// src/commands/db/schema.ts
|
|
15542
15607
|
var import_cli_table32 = __toESM(require_cli_table3(), 1);
|
|
15608
|
+
|
|
15609
|
+
// src/commands/db/json-input.ts
|
|
15610
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
15611
|
+
async function readJsonArgument(value, option, hint) {
|
|
15612
|
+
let text = value;
|
|
15613
|
+
if (value === "-") {
|
|
15614
|
+
const chunks = [];
|
|
15615
|
+
for await (const chunk of process.stdin) {
|
|
15616
|
+
chunks.push(chunk);
|
|
15617
|
+
}
|
|
15618
|
+
text = Buffer.concat(chunks).toString("utf8");
|
|
15619
|
+
} else if (value.startsWith("@")) {
|
|
15620
|
+
text = await readFile8(value.slice(1), "utf8");
|
|
15621
|
+
}
|
|
15622
|
+
try {
|
|
15623
|
+
return JSON.parse(text);
|
|
15624
|
+
} catch {
|
|
15625
|
+
throw new CliError(`${option} is not valid JSON.`, hint ?? "Pass inline JSON, @<file> or - for stdin.");
|
|
15626
|
+
}
|
|
15627
|
+
}
|
|
15628
|
+
|
|
15629
|
+
// src/commands/db/schema.ts
|
|
15630
|
+
var FIELD_REFERENCE_URL = "https://docs.softr.io/softr-api/softr-database-api/table-fields/add-table-field";
|
|
15631
|
+
var TABLE_ARGUMENT = "the table id or exact name";
|
|
15632
|
+
var FIELD_ARGUMENT = "the field id or exact name";
|
|
15633
|
+
function withDatabaseOptions(command) {
|
|
15634
|
+
return command.option("--database <id>", DATABASE_ID_HELP).option("--dir <path>", DATABASE_DIR_HELP);
|
|
15635
|
+
}
|
|
15636
|
+
async function schemaContext(opts) {
|
|
15637
|
+
const target = await resolveDatabase(process.cwd(), opts.database, opts.dir);
|
|
15638
|
+
const client = await authenticatedClient(resolveTarget());
|
|
15639
|
+
const cache = target.dir ? await readSchemaCache(target.dir) : void 0;
|
|
15640
|
+
return { client, databaseId: target.databaseId, dir: target.dir, cache };
|
|
15641
|
+
}
|
|
15642
|
+
async function currentTables(context, fresh) {
|
|
15643
|
+
if (!context.dir) {
|
|
15644
|
+
return listTables(context.client, context.databaseId);
|
|
15645
|
+
}
|
|
15646
|
+
if (!fresh && context.cache) {
|
|
15647
|
+
return context.cache.tables;
|
|
15648
|
+
}
|
|
15649
|
+
context.cache = await refreshSchemaCache(context.client, context.dir, context.databaseId);
|
|
15650
|
+
return context.cache.tables;
|
|
15651
|
+
}
|
|
15652
|
+
function tableIn(context, tables, reference) {
|
|
15653
|
+
const table = byIdOrName(tables, reference, "table");
|
|
15654
|
+
if (!table) {
|
|
15655
|
+
throw new CliError(
|
|
15656
|
+
`Database ${context.databaseId} has no table with the id or name "${reference}".`,
|
|
15657
|
+
'"softr db tables list" shows its tables.'
|
|
15658
|
+
);
|
|
15659
|
+
}
|
|
15660
|
+
return table;
|
|
15661
|
+
}
|
|
15662
|
+
async function findTableOnServer(context, reference) {
|
|
15663
|
+
return tableIn(context, await currentTables(context, true), reference);
|
|
15664
|
+
}
|
|
15665
|
+
async function findTableCached(context, reference) {
|
|
15666
|
+
const cached = context.dir && context.cache ? byIdOrName(context.cache.tables, reference, "table") : void 0;
|
|
15667
|
+
return cached ?? findTableOnServer(context, reference);
|
|
15668
|
+
}
|
|
15669
|
+
async function findField(context, tableReference, reference) {
|
|
15670
|
+
const table = await findTableOnServer(context, tableReference);
|
|
15671
|
+
const field = byIdOrName(table.fields, reference, "field");
|
|
15672
|
+
if (!field) {
|
|
15673
|
+
throw new CliError(
|
|
15674
|
+
`Table ${table.name} has no field with the id or name "${reference}".`,
|
|
15675
|
+
`"softr db tables get ${table.id}" shows its fields.`
|
|
15676
|
+
);
|
|
15677
|
+
}
|
|
15678
|
+
return { table, field };
|
|
15679
|
+
}
|
|
15680
|
+
async function afterSchemaWrite(context) {
|
|
15681
|
+
if (context.dir) {
|
|
15682
|
+
context.cache = await refreshSchemaCache(context.client, context.dir, context.databaseId);
|
|
15683
|
+
}
|
|
15684
|
+
}
|
|
15685
|
+
function parseOptions(json) {
|
|
15686
|
+
if (json === void 0) {
|
|
15687
|
+
return void 0;
|
|
15688
|
+
}
|
|
15689
|
+
try {
|
|
15690
|
+
return JSON.parse(json);
|
|
15691
|
+
} catch {
|
|
15692
|
+
throw new CliError("--options is not valid JSON.", `The options of each field type: ${FIELD_REFERENCE_URL}`);
|
|
15693
|
+
}
|
|
15694
|
+
}
|
|
15695
|
+
function parseFieldSpec(spec) {
|
|
15696
|
+
const colon = spec.lastIndexOf(":");
|
|
15697
|
+
const name = colon > 0 ? spec.slice(0, colon).trim() : "";
|
|
15698
|
+
const type = colon > 0 ? spec.slice(colon + 1).trim().toUpperCase() : "";
|
|
15699
|
+
if (!name || !type) {
|
|
15700
|
+
throw new CliError(`--field "${spec}" must be <name>:<TYPE>, for example "Due date:DATE".`);
|
|
15701
|
+
}
|
|
15702
|
+
return { name, type };
|
|
15703
|
+
}
|
|
15704
|
+
function parseFieldList(value) {
|
|
15705
|
+
if (!Array.isArray(value)) {
|
|
15706
|
+
throw new CliError(
|
|
15707
|
+
"--fields must be a JSON array of fields.",
|
|
15708
|
+
`For example: [{"name": "Stage", "type": "SELECT", "options": {...}}]`
|
|
15709
|
+
);
|
|
15710
|
+
}
|
|
15711
|
+
return value.map((item, index) => {
|
|
15712
|
+
const field = item;
|
|
15713
|
+
if (!field || typeof field !== "object" || typeof field.name !== "string" || !field.name || typeof field.type !== "string" || !field.type) {
|
|
15714
|
+
throw new CliError(`--fields item ${index + 1} needs a "name" and a "type".`);
|
|
15715
|
+
}
|
|
15716
|
+
return { ...field, name: field.name, type: field.type.toUpperCase() };
|
|
15717
|
+
});
|
|
15718
|
+
}
|
|
15719
|
+
function renderTables(tables) {
|
|
15720
|
+
if (!tables.length) {
|
|
15721
|
+
return "The database has no tables. Create one with: softr db tables create <name>";
|
|
15722
|
+
}
|
|
15723
|
+
const table = new import_cli_table32.default(plainTable(["ID", "Name", "Fields", "Primary field"], [18, 34, 8, 30]));
|
|
15724
|
+
for (const item of tables) {
|
|
15725
|
+
const primary = item.fields.find((field) => field.id === item.primaryFieldId);
|
|
15726
|
+
table.push([item.id, item.name, String(item.fields.length), primary?.name ?? item.primaryFieldId]);
|
|
15727
|
+
}
|
|
15728
|
+
return table.toString();
|
|
15729
|
+
}
|
|
15730
|
+
function flags(field, primaryFieldId) {
|
|
15731
|
+
return [
|
|
15732
|
+
field.id === primaryFieldId ? "primary" : "",
|
|
15733
|
+
field.required ? "required" : "",
|
|
15734
|
+
field.readonly ? "read-only" : "",
|
|
15735
|
+
field.allowMultipleEntries ? "multiple" : ""
|
|
15736
|
+
].filter(Boolean).join(", ");
|
|
15737
|
+
}
|
|
15738
|
+
function renderTable(item) {
|
|
15739
|
+
const fields = new import_cli_table32.default(plainTable(["ID", "Name", "Type", ""], [18, 30, 18, 30]));
|
|
15740
|
+
for (const field of item.fields) {
|
|
15741
|
+
fields.push([field.id, field.name, field.type, flags(field, item.primaryFieldId)]);
|
|
15742
|
+
}
|
|
15743
|
+
return [
|
|
15744
|
+
`${item.name} (${item.id})`,
|
|
15745
|
+
...item.description ? [` ${item.description}`] : [],
|
|
15746
|
+
` Default view: ${item.defaultViewId}`,
|
|
15747
|
+
fields.toString()
|
|
15748
|
+
].join("\n");
|
|
15749
|
+
}
|
|
15750
|
+
function renderField(table, field) {
|
|
15751
|
+
return [
|
|
15752
|
+
`${field.name} (${field.id}) in ${table.name}`,
|
|
15753
|
+
...field.description ? [` ${field.description}`] : [],
|
|
15754
|
+
` Type: ${field.type}`,
|
|
15755
|
+
...flags(field, table.primaryFieldId) ? [` Flags: ${flags(field, table.primaryFieldId)}`] : [],
|
|
15756
|
+
` Options: ${JSON.stringify(field.options ?? null)}`
|
|
15757
|
+
].join("\n");
|
|
15758
|
+
}
|
|
15759
|
+
function renderViews(views) {
|
|
15760
|
+
const table = new import_cli_table32.default(plainTable(["ID", "Name"], [18, 50]));
|
|
15761
|
+
for (const view of views) {
|
|
15762
|
+
table.push([view.id, view.name]);
|
|
15763
|
+
}
|
|
15764
|
+
return table.toString();
|
|
15765
|
+
}
|
|
15766
|
+
function registerTables(db2) {
|
|
15767
|
+
const tables = db2.command("tables").description("The tables of a database, with their fields");
|
|
15768
|
+
withDatabaseOptions(tables.command("list").description("List the tables of the database")).action(
|
|
15769
|
+
async (opts, command) => {
|
|
15770
|
+
const options = globalOptions(command);
|
|
15771
|
+
const context = await schemaContext(opts);
|
|
15772
|
+
const items = await currentTables(context, true);
|
|
15773
|
+
emit(options, renderTables(items), { databaseId: context.databaseId, tables: items });
|
|
15774
|
+
}
|
|
15775
|
+
);
|
|
15776
|
+
withDatabaseOptions(
|
|
15777
|
+
tables.command("get").description("Show a table with its fields").argument("<table>", TABLE_ARGUMENT)
|
|
15778
|
+
).action(async (reference, opts, command) => {
|
|
15779
|
+
const options = globalOptions(command);
|
|
15780
|
+
const context = await schemaContext(opts);
|
|
15781
|
+
const table = await findTableOnServer(context, reference);
|
|
15782
|
+
emit(options, renderTable(table), { table });
|
|
15783
|
+
});
|
|
15784
|
+
withDatabaseOptions(
|
|
15785
|
+
tables.command("create").description(
|
|
15786
|
+
"Create a table with at least one field; the first one names a record unless --primary-field says otherwise"
|
|
15787
|
+
).argument("<name>", "the table name").option("--description <text>", "what the table holds").option(
|
|
15788
|
+
"--field <name:TYPE>",
|
|
15789
|
+
"a field of a type without options, repeatable",
|
|
15790
|
+
(value, previous) => [...previous, value],
|
|
15791
|
+
[]
|
|
15792
|
+
).option(
|
|
15793
|
+
"--fields <json>",
|
|
15794
|
+
`fields as a JSON array of {name, type, options?, description?, allowMultipleEntries?}, @<file> or - for stdin; they follow the --field ones (types and options: ${FIELD_REFERENCE_URL})`
|
|
15795
|
+
).option("--primary-field <name>", "the field that names a record (default: the first field)")
|
|
15796
|
+
).action(
|
|
15797
|
+
async (name, opts, command) => {
|
|
15798
|
+
const options = globalOptions(command);
|
|
15799
|
+
const fields = [
|
|
15800
|
+
...opts.field.map(parseFieldSpec),
|
|
15801
|
+
...opts.fields === void 0 ? [] : parseFieldList(await readJsonArgument(opts.fields, "--fields"))
|
|
15802
|
+
];
|
|
15803
|
+
if (!fields.length) {
|
|
15804
|
+
throw new CliError(
|
|
15805
|
+
'A table needs at least one field: pass --field <name>:<TYPE>, for example --field "Name:SINGLE_LINE_TEXT", or --fields with a JSON array.',
|
|
15806
|
+
"The first field names a record unless --primary-field names another."
|
|
15807
|
+
);
|
|
15808
|
+
}
|
|
15809
|
+
if (opts.primaryField && !fields.some((field) => field.name === opts.primaryField)) {
|
|
15810
|
+
throw new CliError(`--primary-field "${opts.primaryField}" is not one of the fields' names.`);
|
|
15811
|
+
}
|
|
15812
|
+
const context = await schemaContext(opts);
|
|
15813
|
+
const table = await createTable(context.client, context.databaseId, {
|
|
15814
|
+
name,
|
|
15815
|
+
description: opts.description,
|
|
15816
|
+
primaryFieldName: opts.primaryField ?? fields[0].name,
|
|
15817
|
+
fields
|
|
15818
|
+
});
|
|
15819
|
+
await afterSchemaWrite(context);
|
|
15820
|
+
emit(options, `Created table ${table.name} (${table.id}) with ${table.fields.length} fields.`, { table });
|
|
15821
|
+
}
|
|
15822
|
+
);
|
|
15823
|
+
withDatabaseOptions(
|
|
15824
|
+
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")
|
|
15825
|
+
).action(
|
|
15826
|
+
async (reference, opts, command) => {
|
|
15827
|
+
if (!opts.name && opts.description === void 0) {
|
|
15828
|
+
throw new CliError("Nothing to change: pass --name, --description or both.");
|
|
15829
|
+
}
|
|
15830
|
+
const options = globalOptions(command);
|
|
15831
|
+
const context = await schemaContext(opts);
|
|
15832
|
+
const current2 = await findTableOnServer(context, reference);
|
|
15833
|
+
const table = await updateTable(context.client, context.databaseId, current2.id, {
|
|
15834
|
+
name: opts.name ?? current2.name,
|
|
15835
|
+
description: opts.description ?? current2.description
|
|
15836
|
+
});
|
|
15837
|
+
await afterSchemaWrite(context);
|
|
15838
|
+
emit(options, `Updated table ${table.name} (${table.id}).`, { table });
|
|
15839
|
+
}
|
|
15840
|
+
);
|
|
15841
|
+
withDatabaseOptions(
|
|
15842
|
+
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")
|
|
15843
|
+
).action(async (reference, opts, command) => {
|
|
15844
|
+
const options = globalOptions(command);
|
|
15845
|
+
const context = await schemaContext(opts);
|
|
15846
|
+
const table = await findTableOnServer(context, reference);
|
|
15847
|
+
await deleteTable(context.client, context.databaseId, table.id, opts.force === true);
|
|
15848
|
+
await afterSchemaWrite(context);
|
|
15849
|
+
emit(options, `Deleted table ${table.name} (${table.id}).`, { deleted: table.id });
|
|
15850
|
+
});
|
|
15851
|
+
}
|
|
15852
|
+
function registerFields(db2) {
|
|
15853
|
+
const fields = db2.command("fields").description("The fields of a table");
|
|
15854
|
+
withDatabaseOptions(
|
|
15855
|
+
fields.command("get").description("Show a field with its options").argument("<table>", TABLE_ARGUMENT).argument("<field>", FIELD_ARGUMENT)
|
|
15856
|
+
).action(async (tableReference, reference, opts, command) => {
|
|
15857
|
+
const options = globalOptions(command);
|
|
15858
|
+
const context = await schemaContext(opts);
|
|
15859
|
+
const { table, field } = await findField(context, tableReference, reference);
|
|
15860
|
+
emit(options, renderField(table, field), { tableId: table.id, field });
|
|
15861
|
+
});
|
|
15862
|
+
withDatabaseOptions(
|
|
15863
|
+
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 (${FIELD_REFERENCE_URL})`).option("--description <text>", "what the field holds").option("--multiple", "allow several values (SELECT, LINKED_RECORD, USER, ATTACHMENT)")
|
|
15864
|
+
).action(
|
|
15865
|
+
async (tableReference, name, opts, command) => {
|
|
15866
|
+
const options = globalOptions(command);
|
|
15867
|
+
const fieldOptions = parseOptions(opts.options);
|
|
15868
|
+
const context = await schemaContext(opts);
|
|
15869
|
+
const table = await findTableCached(context, tableReference);
|
|
15870
|
+
const field = await addField(context.client, context.databaseId, table.id, {
|
|
15871
|
+
name,
|
|
15872
|
+
type: opts.type.toUpperCase(),
|
|
15873
|
+
description: opts.description,
|
|
15874
|
+
...fieldOptions === void 0 ? {} : { options: fieldOptions },
|
|
15875
|
+
allowMultipleEntries: opts.multiple === true
|
|
15876
|
+
});
|
|
15877
|
+
await afterSchemaWrite(context);
|
|
15878
|
+
emit(options, `Added field ${field.name} (${field.id}, ${field.type}) to ${table.name}.`, {
|
|
15879
|
+
tableId: table.id,
|
|
15880
|
+
field
|
|
15881
|
+
});
|
|
15882
|
+
}
|
|
15883
|
+
);
|
|
15884
|
+
withDatabaseOptions(
|
|
15885
|
+
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("--options <json>", `the new options as JSON, replacing the current ones (${FIELD_REFERENCE_URL})`).option("--description <text>", "the new description").option("--multiple", "allow several values").option("--no-multiple", "allow one value only")
|
|
15886
|
+
).action(
|
|
15887
|
+
async (tableReference, reference, opts, command) => {
|
|
15888
|
+
const fieldOptions = parseOptions(opts.options);
|
|
15889
|
+
if (!opts.name && !opts.type && fieldOptions === void 0 && opts.description === void 0 && opts.multiple === void 0) {
|
|
15890
|
+
throw new CliError("Nothing to change: pass --name, --type, --options, --description or --[no-]multiple.");
|
|
15891
|
+
}
|
|
15892
|
+
const options = globalOptions(command);
|
|
15893
|
+
const context = await schemaContext(opts);
|
|
15894
|
+
const { table, field: current2 } = await findField(context, tableReference, reference);
|
|
15895
|
+
const field = await updateField(context.client, context.databaseId, table.id, current2.id, {
|
|
15896
|
+
name: opts.name ?? current2.name,
|
|
15897
|
+
type: opts.type?.toUpperCase() ?? current2.type,
|
|
15898
|
+
description: opts.description ?? current2.description,
|
|
15899
|
+
options: fieldOptions ?? current2.options,
|
|
15900
|
+
aiOptions: current2.aiOptions ?? null,
|
|
15901
|
+
defaultValue: current2.defaultValue ?? null,
|
|
15902
|
+
allowMultipleEntries: opts.multiple ?? current2.allowMultipleEntries
|
|
15903
|
+
});
|
|
15904
|
+
await afterSchemaWrite(context);
|
|
15905
|
+
emit(options, `Updated field ${field.name} (${field.id}, ${field.type}) in ${table.name}.`, {
|
|
15906
|
+
tableId: table.id,
|
|
15907
|
+
field
|
|
15908
|
+
});
|
|
15909
|
+
}
|
|
15910
|
+
);
|
|
15911
|
+
withDatabaseOptions(
|
|
15912
|
+
fields.command("delete").description("Delete a field and its values in every record").argument("<table>", TABLE_ARGUMENT).argument("<field>", FIELD_ARGUMENT)
|
|
15913
|
+
).action(async (tableReference, reference, opts, command) => {
|
|
15914
|
+
const options = globalOptions(command);
|
|
15915
|
+
const context = await schemaContext(opts);
|
|
15916
|
+
const { table, field } = await findField(context, tableReference, reference);
|
|
15917
|
+
await deleteField(context.client, context.databaseId, table.id, field.id);
|
|
15918
|
+
await afterSchemaWrite(context);
|
|
15919
|
+
emit(options, `Deleted field ${field.name} (${field.id}) from ${table.name}.`, {
|
|
15920
|
+
tableId: table.id,
|
|
15921
|
+
deleted: field.id
|
|
15922
|
+
});
|
|
15923
|
+
});
|
|
15924
|
+
}
|
|
15925
|
+
function registerViews(db2) {
|
|
15926
|
+
const views = db2.command("views").description("The views of a table");
|
|
15927
|
+
withDatabaseOptions(
|
|
15928
|
+
views.command("list").description("List the views of a table").argument("<table>", TABLE_ARGUMENT)
|
|
15929
|
+
).action(async (reference, opts, command) => {
|
|
15930
|
+
const options = globalOptions(command);
|
|
15931
|
+
const context = await schemaContext(opts);
|
|
15932
|
+
const table = await findTableOnServer(context, reference);
|
|
15933
|
+
const items = await listViews(context.client, context.databaseId, table.id);
|
|
15934
|
+
if (context.dir) {
|
|
15935
|
+
await writeViewsCache(context.dir, table.id, items);
|
|
15936
|
+
}
|
|
15937
|
+
emit(options, renderViews(items), { tableId: table.id, views: items });
|
|
15938
|
+
});
|
|
15939
|
+
}
|
|
15940
|
+
|
|
15941
|
+
// src/commands/integrations.ts
|
|
15942
|
+
var import_cli_table33 = __toESM(require_cli_table3(), 1);
|
|
15543
15943
|
import path12 from "node:path";
|
|
15544
15944
|
function toRow(integration) {
|
|
15545
15945
|
return {
|
|
@@ -15558,7 +15958,7 @@ function renderIntegrations(rows) {
|
|
|
15558
15958
|
if (!rows.length) {
|
|
15559
15959
|
return "No integrations connected in this workspace. Connect one in the studio (Workspace settings > Integrations).";
|
|
15560
15960
|
}
|
|
15561
|
-
const table = new
|
|
15961
|
+
const table = new import_cli_table33.default({
|
|
15562
15962
|
head: ["ID", "Name", "Type", "Account", "Auth"],
|
|
15563
15963
|
colWidths: [38, 34, 22, 30, 11],
|
|
15564
15964
|
wordWrap: true,
|
|
@@ -15610,7 +16010,7 @@ ${renderIntegrations(rows)}`, {
|
|
|
15610
16010
|
}
|
|
15611
16011
|
|
|
15612
16012
|
// src/commands/list.ts
|
|
15613
|
-
var
|
|
16013
|
+
var import_cli_table34 = __toESM(require_cli_table3(), 1);
|
|
15614
16014
|
function toRow2(workflow, workspace) {
|
|
15615
16015
|
return {
|
|
15616
16016
|
id: workflow.id,
|
|
@@ -15652,7 +16052,7 @@ async function collectWorkflows(client, { workspaceId, applicationId } = {}) {
|
|
|
15652
16052
|
}
|
|
15653
16053
|
var TITLE_WIDTH = 34;
|
|
15654
16054
|
function workflowTable(rows) {
|
|
15655
|
-
const table = new
|
|
16055
|
+
const table = new import_cli_table34.default({
|
|
15656
16056
|
head: ["ID", "Title", "Triggers", "Status", "Version", "Draft"],
|
|
15657
16057
|
// Only the free-text title wraps; the other columns size to their content, so trigger types are never cut off.
|
|
15658
16058
|
colWidths: [null, TITLE_WIDTH, null, null, null, null],
|
|
@@ -15973,7 +16373,7 @@ ${identity.statements.map((s) => ` ${s.actions.join(", ")} on ${s.resources.joi
|
|
|
15973
16373
|
}
|
|
15974
16374
|
|
|
15975
16375
|
// src/commands/outputs.ts
|
|
15976
|
-
var
|
|
16376
|
+
var import_cli_table36 = __toESM(require_cli_table3(), 1);
|
|
15977
16377
|
|
|
15978
16378
|
// src/project/test-state.ts
|
|
15979
16379
|
function outdatedReferences(row) {
|
|
@@ -16022,7 +16422,7 @@ function collectVariables(nodeId, sample, metadata) {
|
|
|
16022
16422
|
}
|
|
16023
16423
|
|
|
16024
16424
|
// src/commands/test.ts
|
|
16025
|
-
var
|
|
16425
|
+
var import_cli_table35 = __toESM(require_cli_table3(), 1);
|
|
16026
16426
|
var OUTPUTS_FILE = "outputs.json";
|
|
16027
16427
|
function fieldCount(row) {
|
|
16028
16428
|
const output = row.sampleOutput?.result?.output;
|
|
@@ -16123,7 +16523,7 @@ var LABEL = {
|
|
|
16123
16523
|
error: "ERROR"
|
|
16124
16524
|
};
|
|
16125
16525
|
function renderResults(results) {
|
|
16126
|
-
const table = new
|
|
16526
|
+
const table = new import_cli_table35.default({
|
|
16127
16527
|
head: ["Result", "Node", "Type", "Detail"],
|
|
16128
16528
|
colWidths: [9, 30, 24, 60],
|
|
16129
16529
|
wordWrap: true,
|
|
@@ -16239,7 +16639,7 @@ function sampleState(row) {
|
|
|
16239
16639
|
}
|
|
16240
16640
|
}
|
|
16241
16641
|
function renderVariables(nodeId, entries, unverified) {
|
|
16242
|
-
const table = new
|
|
16642
|
+
const table = new import_cli_table36.default({
|
|
16243
16643
|
head: ["Variable", "Type", "Example"],
|
|
16244
16644
|
colWidths: [64, 32, 44],
|
|
16245
16645
|
wordWrap: true,
|
|
@@ -16307,7 +16707,7 @@ function registerOutputs(program3) {
|
|
|
16307
16707
|
outdated: Object.keys(outdatedReferences(row))
|
|
16308
16708
|
};
|
|
16309
16709
|
});
|
|
16310
|
-
const table = new
|
|
16710
|
+
const table = new import_cli_table36.default({
|
|
16311
16711
|
head: ["Node", "Type", "Sample", "Fields"],
|
|
16312
16712
|
colWidths: [30, 24, 60, 8],
|
|
16313
16713
|
wordWrap: true,
|
|
@@ -16876,10 +17276,10 @@ ${unbacked.map(
|
|
|
16876
17276
|
}
|
|
16877
17277
|
|
|
16878
17278
|
// src/commands/spec.ts
|
|
16879
|
-
var
|
|
17279
|
+
var import_cli_table37 = __toESM(require_cli_table3(), 1);
|
|
16880
17280
|
var TABLE_STYLE2 = { head: [], border: [], "padding-left": 1, "padding-right": 1 };
|
|
16881
17281
|
function renderList() {
|
|
16882
|
-
const table = new
|
|
17282
|
+
const table = new import_cli_table37.default({
|
|
16883
17283
|
head: ["Type", "Kind", "Label", "Summary"],
|
|
16884
17284
|
colWidths: [40, 9, 24, 70],
|
|
16885
17285
|
wordWrap: true,
|
|
@@ -16907,7 +17307,7 @@ function renderEntry(entry) {
|
|
|
16907
17307
|
const blocks = [`${entry.type} (${entry.kind}) \u2014 ${entry.label}`, entry.summary, `Docs: ${entry.docs}`];
|
|
16908
17308
|
const inputs = Object.entries(entry.inputs);
|
|
16909
17309
|
if (inputs.length) {
|
|
16910
|
-
const table = new
|
|
17310
|
+
const table = new import_cli_table37.default({
|
|
16911
17311
|
head: ["Input", "Type", "Required", "Description"],
|
|
16912
17312
|
colWidths: [20, 9, 10, 90],
|
|
16913
17313
|
wordWrap: true,
|
|
@@ -17157,14 +17557,14 @@ ${item.lines.map((line) => ` ${line}`).join("\n")}`
|
|
|
17157
17557
|
}
|
|
17158
17558
|
|
|
17159
17559
|
// src/commands/workspaces.ts
|
|
17160
|
-
var
|
|
17560
|
+
var import_cli_table38 = __toESM(require_cli_table3(), 1);
|
|
17161
17561
|
function registerWorkspaces(program3) {
|
|
17162
17562
|
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
17563
|
const options = globalOptions(command);
|
|
17164
17564
|
const target = resolveTarget();
|
|
17165
17565
|
const client = await authenticatedClient(target);
|
|
17166
17566
|
const workspaces = await listWorkspaces(client);
|
|
17167
|
-
const table = new
|
|
17567
|
+
const table = new import_cli_table38.default({
|
|
17168
17568
|
head: ["ID", "Name", "Role", "Default", "Scopes"],
|
|
17169
17569
|
colWidths: [38, 26, 10, 9, 34],
|
|
17170
17570
|
wordWrap: true,
|
|
@@ -17191,7 +17591,7 @@ Pass --workspace <id> to a command, or set SOFTR_WORKSPACE_ID, to work in one of
|
|
|
17191
17591
|
// package.json
|
|
17192
17592
|
var package_default = {
|
|
17193
17593
|
name: "@softr/cli",
|
|
17194
|
-
version: "0.1.
|
|
17594
|
+
version: "0.1.5",
|
|
17195
17595
|
description: "The Softr command line: build, test and publish Softr workflows from local files, manage Softr Databases; more Softr APIs to come",
|
|
17196
17596
|
keywords: [
|
|
17197
17597
|
"softr",
|
|
@@ -17219,7 +17619,7 @@ var package_default = {
|
|
|
17219
17619
|
format: "prettier --write .",
|
|
17220
17620
|
"format:check": "prettier --check .",
|
|
17221
17621
|
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"
|
|
17622
|
+
"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
17623
|
},
|
|
17224
17624
|
publishConfig: {
|
|
17225
17625
|
access: "public"
|
|
@@ -17264,4 +17664,7 @@ registerSpec(workflows);
|
|
|
17264
17664
|
registerSchema(workflows);
|
|
17265
17665
|
var db = program2.command("db").description("Manage Softr Databases: databases, their tables, fields and records");
|
|
17266
17666
|
registerDatabases(db);
|
|
17667
|
+
registerTables(db);
|
|
17668
|
+
registerFields(db);
|
|
17669
|
+
registerViews(db);
|
|
17267
17670
|
program2.parseAsync(process.argv).catch(reportError);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softr/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The Softr command line: build, test and publish Softr workflows from local files, manage Softr Databases; more Softr APIs to come",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"softr",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"format": "prettier --write .",
|
|
29
29
|
"format:check": "prettier --check .",
|
|
30
30
|
"check": "npm run typecheck && npm run format:check && npm test && npm run build",
|
|
31
|
-
"check:skill": "npx -y skills-ref@0.1.5 validate skills/softr-cli && npx -y skills-ref@0.1.5 validate skills/softr-workflows"
|
|
31
|
+
"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"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|