@getxflow/cli 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: xflow
3
- description: Build, deploy and publish apps on the XFlow platform with the xflow CLI. Use when the project root has xflow.json or VITE_XFLOW_* variables, when asked to deploy, publish, roll back a version, sync sources with the platform, look into errors from a deployed app, or build UI on the platform design system.
3
+ description: Build, deploy and publish apps on the XFlow platform with the xflow CLI. Use whenever the project root has xflow.json or VITE_XFLOW_* variables, and for any task that touches deployment, publishing, rollback, source sync, the project database or SQL migrations, cloud functions, schedules, environment variables and secrets, production errors and logs, or UI built on the platform design system.
4
4
  ---
5
5
 
6
6
  # XFlow
@@ -22,19 +22,68 @@ contains the fix. Help output is in Russian.
22
22
  2. `npm run typecheck` for a two-second type check (older projects may not have the
23
23
  script, then `npx tsc --noEmit`).
24
24
  3. `npm run build` if the change is substantial, before deploying.
25
- 4. `xflow deploy` sends the sources, builds locally, uploads the version. It prints
26
- a URL: that is the dev address, visible to the team, not to visitors.
27
- 5. Open and check it: the URL from the output, or `xflow open`.
25
+ 4. `xflow deploy` sends the sources and builds them on the platform, printing each
26
+ phase and the six-digit number of the version it built.
27
+ 5. Give the user the project link the CLI printed and let them look. Do not open a
28
+ browser for them.
28
29
  6. `xflow publish` makes that same version visible to visitors.
29
30
 
30
31
  The split is deliberate: shipping a build and showing it are two separate decisions.
31
32
  Until `publish` runs, visitors keep seeing the previous version.
32
33
 
33
34
  Rolling back: `xflow deployments` lists the version history, `xflow rollback <id>`
34
- points the dev address back at an earlier build. Sources stay on their own revision.
35
-
36
- The build runs on the developer machine. The platform has no builder, it serves
37
- static files: a build without `index.html` in the root is rejected.
35
+ points the project back at an earlier build. Sources stay on their own revision.
36
+
37
+ **The only link you give a person is the project page**, `https://app.getxflow.com/projects/<id>`,
38
+ which the CLI prints for you. Refer to builds by their number ("version 481203 is built,
39
+ 092399 is what visitors see"), never by address. The platform does not hand out build
40
+ addresses and neither should you: a build address has the version number baked into it,
41
+ and after the next publish it does not break, it keeps answering with the old copy. Anyone
42
+ holding that link then stares at a frozen app and concludes the changes never shipped. The
43
+ project page always shows the current state, and every version is reachable from it.
44
+
45
+ The platform builds the project itself, in a clean sandbox with one Node version for
46
+ everyone, and serves the result as static files. Nothing is built on your machine for
47
+ deployment, so a local `npm run build` is only a fast way to see errors early.
48
+
49
+ ## Build gate
50
+
51
+ Before the sandbox starts, the platform checks the sources against the template. Every
52
+ rule below blocks the build, and the whole list of violations comes back at once, with
53
+ files and line numbers. Nothing is charged for a rejected attempt: the sandbox never
54
+ starts. Write code that already satisfies these rules instead of learning them from
55
+ rejections.
56
+
57
+ Build setup:
58
+
59
+ - `package.json` with the build script named in `xflow.json` (`npm run build` by default).
60
+ - Vite: a `vite.config.*` and `vite` in dependencies.
61
+ - No server frameworks: `next`, `nuxt`, `remix`, `@sveltejs/kit`, `astro`.
62
+ - `index.html` in the root, `src/main.tsx` as the entry point.
63
+ - Application code under `src/`. Root `app/`, `pages/`, `next/` are rejected.
64
+
65
+ Platform contract, checked across all of `src/`:
66
+
67
+ - Call cloud functions through `xflow.functions.invoke`, never through a hardcoded
68
+ `*.yandexcloud.net` URL: the address changes and the app breaks silently.
69
+ - No API keys or tokens in the source: they end up in the bundle. Put the call in a
70
+ cloud function and the key in project secrets.
71
+ - No server modules (`fs`, `express`, `http`, `child_process`): there is no server runtime.
72
+
73
+ Interface rules, checked outside `src/components/ui` and `src/components/blocks`:
74
+
75
+ - No `alert()`, `confirm()`, `prompt()`. Use the Dialog and Toast components.
76
+ - No `console.log`. Deployed apps have a public console, and forgotten debugging prints
77
+ user data into it. `console.error` and `console.warn` are fine, they reach the project
78
+ logs.
79
+ - No inline styles with literal values (`style={{ color: '#fff' }}`). Computed styles
80
+ (a drag transform, a progress width) are fine, Tailwind cannot express them.
81
+ - No hex colors or Tailwind palette classes (`text-gray-500`): use the theme tokens.
82
+ Charts are exempt, they need real colors.
83
+ - No importing a `@/components/ui/*` component that does not exist in the project.
84
+ - A library that needs a provider (`@tanstack/react-query`, `react-redux`, `sonner`,
85
+ `react-hot-toast`, `react-dnd`) must have it mounted in `App.tsx`. Missing providers
86
+ build fine and give visitors a white screen.
38
87
 
39
88
  ## Cloud functions
40
89
 
@@ -58,8 +107,14 @@ and needs `xflow deploy` again.
58
107
  Treat a function as a public API: the token ships inside the frontend bundle, so anyone
59
108
  who opens the app can call it.
60
109
 
61
- Organization secrets reach a function only if it mentions them via `process.env`, so
62
- read them by name and do not build variable names dynamically.
110
+ Keys and passwords live on the platform, not in the repository: `xflow env set SMTP_PASSWORD=…`
111
+ writes one, `xflow env` lists the names, `xflow env check` tells you which variables your
112
+ functions read but the platform does not have. Values never come back out — the only place
113
+ they exist is inside the running function.
114
+
115
+ A function receives only the variables it mentions by name via `process.env.NAME`, so never
116
+ assemble a variable name from an expression. New values arrive on the next
117
+ `xflow functions deploy`, not at the moment they are written.
63
118
 
64
119
  To run a function on a timer: `xflow schedules set report "0 3 ? * * *"` (daily at 03:00).
65
120
  Six fields, UTC, and exactly one of day-of-month / day-of-week must be `?` — that is
@@ -72,6 +127,18 @@ in filename order by `xflow db migrate`. `xflow db status` shows what is applied
72
127
  waits. History lives in the database itself, so an already applied file is never re-run and
73
128
  editing it changes nothing: write a new migration instead.
74
129
 
130
+ The browser never reaches the database directly. The app reads and writes through a cloud
131
+ function, and inside the handler the connection string is already there:
132
+
133
+ ```js
134
+ const { Client } = require('pg')
135
+ const db = new Client({ connectionString: process.env.DATABASE_URL })
136
+ ```
137
+
138
+ The platform passes `DATABASE_URL` only to functions that mention it, and sets the project
139
+ schema on every connection, so plain table names (`select * from tasks`) hit your project.
140
+ You never write that variable yourself: `xflow env set DATABASE_URL=...` is refused.
141
+
75
142
  The platform keeps no database history and no backups. Anything that destroys data
76
143
  (`DROP TABLE`, `DROP COLUMN`, `TRUNCATE`, `DELETE FROM` without a condition) is refused
77
144
  unless you pass `--allow-destructive`, and with that flag the affected tables are dumped
@@ -91,6 +158,21 @@ Fetch their work next to yours (`xflow pull --into ./server-copy`), merge it loc
91
158
  then push again. `--force` destroys their work: a last resort, not a way around the
92
159
  error.
93
160
 
161
+ ## Direct access without the terminal
162
+
163
+ The platform also exposes an MCP server, connected with `xflow mcp install`. When its tools
164
+ are available, prefer them for control-plane work: project state, database schema and
165
+ read-only queries, migrations, function logs and invocations, schedules, environment
166
+ variables, versions, publish and rollback. They answer with aggregates and say explicitly
167
+ when a result is truncated, which parsing terminal output does not.
168
+
169
+ Code never travels through those tools. Sending sources and deploying functions stay in
170
+ the CLI (`xflow push`, `xflow functions deploy`): pulling a repository through tool calls
171
+ burns the user's tokens for nothing. Building is available through the tools, because it
172
+ runs from the revision already stored on the server: `deployments action=build` starts it
173
+ and answers immediately, `action=status` reports the phase. A build takes minutes, so
174
+ never expect the starting call to return a finished version.
175
+
94
176
  ## Do not
95
177
 
96
178
  - Edit `xflow.json` by hand: the CLI writes it.
package/dist/open-url.js DELETED
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openUrl = openUrl;
4
- const node_child_process_1 = require("node:child_process");
5
- /**
6
- * Открыть адрес в браузере пользователя.
7
- *
8
- * Best-effort: на сервере без графики открывать нечего, и это не ошибка —
9
- * вызывающий в любом случае печатает ссылку рядом.
10
- */
11
- function openUrl(url) {
12
- try {
13
- const command = process.platform === 'win32' ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open';
14
- const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
15
- const child = (0, node_child_process_1.spawn)(command, args, { stdio: 'ignore', detached: true });
16
- child.on('error', () => {
17
- // Браузера нет — молча, ссылка уже показана.
18
- });
19
- child.unref();
20
- }
21
- catch {
22
- // То же самое: открыть не удалось, но команда не про это.
23
- }
24
- }