@getxflow/cli 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/db.js +23 -6
- package/dist/commands/deploy.js +4 -1
- package/dist/flags.js +1 -1
- package/dist/help.js +9 -10
- package/dist/version.js +1 -1
- package/package.json +24 -24
- package/skills/xflow/SKILL.md +729 -728
package/dist/commands/db.js
CHANGED
|
@@ -6,6 +6,7 @@ exports.dbSchema = dbSchema;
|
|
|
6
6
|
exports.dbQuery = dbQuery;
|
|
7
7
|
exports.dbMove = dbMove;
|
|
8
8
|
exports.dbMigrate = dbMigrate;
|
|
9
|
+
exports.migrateBeforeDeploy = migrateBeforeDeploy;
|
|
9
10
|
const node_fs_1 = require("node:fs");
|
|
10
11
|
const node_path_1 = require("node:path");
|
|
11
12
|
const api_1 = require("../api");
|
|
@@ -244,7 +245,7 @@ async function dbQuery(args) {
|
|
|
244
245
|
const { projectId, client } = await (0, session_1.projectTarget)(args);
|
|
245
246
|
const data = await (0, api_1.apiJson)(client, `/api/v1/projects/${projectId}/db/query`, {
|
|
246
247
|
method: 'POST',
|
|
247
|
-
body: { sql
|
|
248
|
+
body: { sql },
|
|
248
249
|
timeoutMs: 60_000,
|
|
249
250
|
});
|
|
250
251
|
// The whole values, machine-readable, and the only thing printed: --json silences
|
|
@@ -272,11 +273,10 @@ async function dbQuery(args) {
|
|
|
272
273
|
}
|
|
273
274
|
if (data.truncated) {
|
|
274
275
|
// No exact total here: the platform stops reading at limit + 1 rows, so all
|
|
275
|
-
// it knows is that more exist.
|
|
276
|
-
// the flag still has room below the ceiling.
|
|
276
|
+
// it knows is that more exist.
|
|
277
277
|
const room = data.limit !== undefined && data.limit_max !== undefined && data.limit < data.limit_max;
|
|
278
278
|
(0, ui_1.note)((0, ui_1.dim)(room
|
|
279
|
-
? ` Shown the first ${data.rows.length} rows, more exist:
|
|
279
|
+
? ` Shown the first ${data.rows.length} rows, more exist: end the query with a larger limit (up to ${data.limit_max}), or narrow it`
|
|
280
280
|
: ` Shown the first ${data.rows.length} rows, more exist: narrow the query, with a where clause or an offset`));
|
|
281
281
|
}
|
|
282
282
|
}
|
|
@@ -345,13 +345,30 @@ async function dbMigrate(args) {
|
|
|
345
345
|
// without functions would lose them from its history, and a clone would miss them.
|
|
346
346
|
if (!dryRun)
|
|
347
347
|
await (0, sources_1.pushSources)({ kind: 'project', root, projectId: config.projectId }, client, { force: false });
|
|
348
|
+
await migrate(client, config.projectId, migrations, dryRun, (0, args_1.flagBool)(args, 'allow-destructive'));
|
|
349
|
+
}
|
|
350
|
+
/** The functions deploy runs this first: new code must not meet an old schema. */
|
|
351
|
+
async function migrateBeforeDeploy(client, root, projectId) {
|
|
352
|
+
const migrations = readMigrations(root);
|
|
353
|
+
if (migrations.length === 0)
|
|
354
|
+
return;
|
|
355
|
+
try {
|
|
356
|
+
await migrate(client, projectId, migrations, false, false);
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
(0, ui_1.warn)('The functions were not deployed: the migrations stopped first');
|
|
360
|
+
(0, ui_1.note)((0, ui_1.dim)(' Once xflow db migrate goes through, deploy again'));
|
|
361
|
+
throw e;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
async function migrate(client, projectId, migrations, dryRun, allowDestructive) {
|
|
348
365
|
(0, ui_1.step)(dryRun ? `Checking the migrations (${migrations.length} in the directory)` : `Applying the migrations (${migrations.length} in the directory)`);
|
|
349
|
-
const result = await (0, api_1.apiJson)(client, `/api/v1/projects/${
|
|
366
|
+
const result = await (0, api_1.apiJson)(client, `/api/v1/projects/${projectId}/db/migrate`, {
|
|
350
367
|
method: 'POST',
|
|
351
368
|
body: {
|
|
352
369
|
migrations,
|
|
353
370
|
dry_run: dryRun,
|
|
354
|
-
allow_destructive:
|
|
371
|
+
allow_destructive: allowDestructive,
|
|
355
372
|
},
|
|
356
373
|
timeoutMs: 300_000,
|
|
357
374
|
});
|
package/dist/commands/deploy.js
CHANGED
|
@@ -14,6 +14,7 @@ const prompt_1 = require("../prompt");
|
|
|
14
14
|
const session_1 = require("../session");
|
|
15
15
|
const tree_1 = require("../tree");
|
|
16
16
|
const ui_1 = require("../ui");
|
|
17
|
+
const db_1 = require("./db");
|
|
17
18
|
const sources_1 = require("./sources");
|
|
18
19
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
19
20
|
/** Slightly longer than the platform's own build timeout. */
|
|
@@ -166,7 +167,7 @@ async function warnUndeployedRoot(client, projectRoot, projectId) {
|
|
|
166
167
|
const relation = server ? (0, tree_1.syncState)(tree.hash, server.tree_hash, (0, config_1.readState)(projectRoot).treeHash) : 'local-changes';
|
|
167
168
|
if (relation !== 'matches') {
|
|
168
169
|
(0, ui_1.warn)('The project root holds changes nobody deployed (functions, migrations or callers)');
|
|
169
|
-
(0, ui_1.note)((0, ui_1.dim)(' If this app needs them: xflow
|
|
170
|
+
(0, ui_1.note)((0, ui_1.dim)(' If this app needs them: xflow deploy functions first, it applies the migrations too'));
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
catch {
|
|
@@ -199,6 +200,8 @@ async function deployTarget(target, args, comment, revision) {
|
|
|
199
200
|
: { kind: 'project', root: target.root, projectId: target.projectId };
|
|
200
201
|
revision = (await (0, sources_1.pushSources)(stream, client, { force: (0, args_1.flagBool)(args, 'force') })).revision;
|
|
201
202
|
}
|
|
203
|
+
if (target.kind === 'project')
|
|
204
|
+
await (0, db_1.migrateBeforeDeploy)(client, target.root, target.projectId);
|
|
202
205
|
}
|
|
203
206
|
(0, ui_1.step)(target.kind === 'app' ? `Building the app from revision ${revision}` : `Deploying the functions from revision ${revision}`);
|
|
204
207
|
const started = await startBuild(client, base, revision, (0, args_1.flagBool)(args, 'allow-removals'), comment);
|
package/dist/flags.js
CHANGED
|
@@ -80,7 +80,7 @@ exports.KNOWN = {
|
|
|
80
80
|
'db status': ['project'],
|
|
81
81
|
'db list': [],
|
|
82
82
|
'db schema': ['project'],
|
|
83
|
-
'db query': ['
|
|
83
|
+
'db query': ['json', 'project'],
|
|
84
84
|
'db migrate': ['dry-run', 'allow-destructive'],
|
|
85
85
|
'db move': ['to', 'confirm', 'project'],
|
|
86
86
|
storage: ['json', 'project'],
|
package/dist/help.js
CHANGED
|
@@ -343,8 +343,8 @@ will work.`,
|
|
|
343
343
|
xflow db status what is applied, what is waiting, the server
|
|
344
344
|
xflow db list databases of the projects, the servers of the organization
|
|
345
345
|
xflow db schema [table] tables of the project, or the columns of one
|
|
346
|
-
xflow db query 'select ...' read data (
|
|
347
|
-
--json prints the values whole)
|
|
346
|
+
xflow db query 'select ...' read data (rows: the query's own limit, 50 without
|
|
347
|
+
one, 300 at most; --json prints the values whole)
|
|
348
348
|
xflow db query <file>.sql the same, the query read from a file
|
|
349
349
|
xflow db migrate store the project root, then apply migrations/*.sql
|
|
350
350
|
xflow db move --to <server> --confirm <project name>
|
|
@@ -718,8 +718,8 @@ git's job.
|
|
|
718
718
|
--force overwrite the folder completely`,
|
|
719
719
|
deploy: `${(0, ui_1.bold)('xflow deploy')}: deploy the functions or build an app, then publish
|
|
720
720
|
|
|
721
|
-
xflow deploy functions -m "…" send the project root, check it,
|
|
722
|
-
and their callers
|
|
721
|
+
xflow deploy functions -m "…" send the project root, check it, apply the new
|
|
722
|
+
migrations, ship the functions and their callers
|
|
723
723
|
xflow deploy apps/<folder> -m "…" send one app and build it; inside its folder a plain
|
|
724
724
|
xflow deploy does the same
|
|
725
725
|
xflow publish [build] point the app address at the newest build, or a named one
|
|
@@ -760,11 +760,13 @@ keys in the code, alert instead of a dialog) is printed as a list and nothing st
|
|
|
760
760
|
merely unfinished (the template page title, no icon) goes through and prints a line
|
|
761
761
|
${(0, ui_1.bold)('Unfinished:')}. Fix it before telling the person the app is done.
|
|
762
762
|
|
|
763
|
-
${(0, ui_1.bold)('deploy functions')}
|
|
763
|
+
${(0, ui_1.bold)('deploy functions')} first applies the new migrations of ${(0, ui_1.bold)('migrations/')}: if one fails or
|
|
764
|
+
would destroy data, nothing ships, and ${(0, ui_1.bold)('xflow db migrate')} is where that gets settled. Then it
|
|
765
|
+
bundles everything in ${(0, ui_1.bold)('functions/<name>/index.ts')}. A function whose
|
|
764
766
|
code and variables did not change is left alone, and one that fails to ship fails the whole
|
|
765
767
|
deploy. It then records the callers and prints which functions are open to the whole
|
|
766
|
-
internet now. A change that touches data and screens goes in this order: the
|
|
767
|
-
the
|
|
768
|
+
internet now. A change that touches data and screens goes in this order: the functions
|
|
769
|
+
(with the migration), then every app that shows it; an app deploy warns when the root holds
|
|
768
770
|
changes nobody deployed.
|
|
769
771
|
|
|
770
772
|
A function gone from the sources would be deleted from the cloud along with its keys and
|
|
@@ -774,9 +776,6 @@ to agree. If the sources hold no functions at all while the cloud holds several,
|
|
|
774
776
|
is deleted and nothing is asked: that looks like a directory which never made it (a
|
|
775
777
|
${(0, ui_1.bold)('functions/')} line in .xflowignore) rather than a decision.
|
|
776
778
|
|
|
777
|
-
The database is not part of this: migrations change data in ways nothing can undo, so
|
|
778
|
-
they stay their own command (${(0, ui_1.bold)('xflow db migrate')}).
|
|
779
|
-
|
|
780
779
|
A build of an app is not shown to visitors until ${(0, ui_1.bold)('xflow publish')}: publishing points the
|
|
781
780
|
app address at a build and takes a second, and an older kept build is the rollback. Only
|
|
782
781
|
the app moves: the functions and the database are one per project and stay as they are.
|
package/dist/version.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_API_URL = exports.CLI_VERSION = void 0;
|
|
4
4
|
/** Keep in sync with cli/package.json. */
|
|
5
|
-
exports.CLI_VERSION = '1.0
|
|
5
|
+
exports.CLI_VERSION = '1.1.0';
|
|
6
6
|
/** Overridden by XFLOW_API_URL or the `api` field in xflow.json. */
|
|
7
7
|
exports.DEFAULT_API_URL = 'https://app.getxflow.com';
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@getxflow/cli",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "CLI for the XFlow platform: projects with apps, functions and a database; source sync, deployment and publishing",
|
|
5
|
-
"license": "UNLICENSED",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=20"
|
|
8
|
-
},
|
|
9
|
-
"bin": {
|
|
10
|
-
"xflow": "dist/bin.js"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"skills"
|
|
15
|
-
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
18
|
-
"build": "npm run clean && tsc -p tsconfig.json",
|
|
19
|
-
"prepublishOnly": "npm run build"
|
|
20
|
-
},
|
|
21
|
-
"publishConfig": {
|
|
22
|
-
"access": "public"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@getxflow/cli",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "CLI for the XFlow platform: projects with apps, functions and a database; source sync, deployment and publishing",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"xflow": "dist/bin.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"skills"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
18
|
+
"build": "npm run clean && tsc -p tsconfig.json",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
}
|
|
24
|
+
}
|