@getxflow/cli 0.31.0 → 0.32.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.
@@ -9,11 +9,12 @@ const errors_1 = require("../errors");
9
9
  const json_arg_1 = require("../json-arg");
10
10
  const session_1 = require("../session");
11
11
  const ui_1 = require("../ui");
12
- /** Who can call the function: inside the app only, or an outside service holding a key. */
12
+ /** Who can call the function: anyone, an outside service holding a key, or the app alone. */
13
13
  function accessLabel(fn) {
14
- if (!fn.external_keys)
15
- return 'in-app only';
16
- return `external (${fn.external_keys} key${fn.external_keys > 1 ? 's' : ''})`;
14
+ const keys = fn.external_keys ? `external (${fn.external_keys} key${fn.external_keys > 1 ? 's' : ''})` : '';
15
+ if (fn.is_public)
16
+ return keys ? `public, ${keys}` : 'public';
17
+ return keys || 'in-app only';
17
18
  }
18
19
  const FUNCTIONS_DIR = 'functions';
19
20
  async function functionsList(args) {
@@ -28,6 +29,9 @@ async function functionsList(args) {
28
29
  fn.status === 'deployed' ? 'deployed' : fn.status === 'failed' ? 'failed' : fn.status,
29
30
  accessLabel(fn),
30
31
  fn.last_deployed_at ? (0, ui_1.formatAge)(fn.last_deployed_at) : '-',
32
+ // The address is not a secret (the app bundle carries it): a page or a
33
+ // webhook needs it, and asking the user to copy it out of the UI was a detour.
34
+ fn.invoke_url ?? '',
31
35
  fn.error_message ?? '',
32
36
  ]));
33
37
  }
@@ -50,7 +54,7 @@ function prettyBody(text) {
50
54
  * this package ships without dependencies and cannot reach into the platform. One test
51
55
  * holds the two halves together.
52
56
  */
53
- const WRAPPER_REASONS = ['no_pass', 'invalid', 'expired', 'no_access', 'unavailable', 'role'];
57
+ const WRAPPER_REASONS = ['no_pass', 'invalid', 'expired', 'no_access', 'unavailable', 'role', 'access'];
54
58
  /** What to look at next, when the function did not answer with a success. */
55
59
  function failureHint(name, status, body) {
56
60
  let reason;
package/dist/help.js CHANGED
@@ -64,7 +64,7 @@ ${(0, ui_1.bold)('Releasing')}
64
64
  xflow deployments version history
65
65
 
66
66
  ${(0, ui_1.bold)('Functions')}
67
- xflow functions list what is deployed (they ship with xflow deploy)
67
+ xflow functions list what is deployed, who may call it, the address
68
68
  xflow functions invoke <name> [--data '{"a":1}']
69
69
  call a function and print the answer
70
70
  xflow functions logs [name] function crashes: stack and console output
@@ -261,13 +261,14 @@ build it and upload what the build writes. Dot entries are skipped. At most 5 MB
261
261
  unpacked and 1000 files.
262
262
 
263
263
  The page is public, so a file holding a secret key is refused whole: every visitor would read
264
- it. A function key is the exception: it opens that one function to every visitor, which is
265
- what a form on a landing page needs. Search engines are asked not to index pages, so do not
266
- promise SEO.
267
-
268
- A page takes the key of the whole organization, the one ${(0, ui_1.bold)('xflow login')} issues. The
269
- section is in beta: XFlow support switches it on for an organization. Switching a page off
270
- and deleting it are for a person, in the platform interface.`,
264
+ it. A page that needs a backend (a form, a lookup) calls a cloud function that declares
265
+ ${(0, ui_1.bold)("exports.access = 'public'")}: such a function answers without a pass and without a
266
+ key, and the page calls its address directly (${(0, ui_1.bold)('xflow functions list')} prints it). No
267
+ key is baked into the page. Search engines are asked not to index pages, so do not promise SEO.
268
+
269
+ A page takes the key of the whole organization, the one ${(0, ui_1.bold)('xflow login')} issues: a key
270
+ scoped to projects is refused. Switching a page off and deleting it are for a person, in the
271
+ platform interface.`,
271
272
  update: `${(0, ui_1.bold)('xflow update')}: bring the CLI up to date
272
273
 
273
274
  Installs the published version and, if anything changed, rewrites the platform
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 = '0.31.0';
5
+ exports.CLI_VERSION = '0.32.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@getxflow/cli",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "CLI for the XFlow platform: source sync, deployment and publishing of applications",
5
5
  "license": "UNLICENSED",
6
6
  "engines": {
@@ -22,7 +22,7 @@ contains the fix.
22
22
 
23
23
  ## Keeping these instructions current
24
24
 
25
- These instructions ship with xflow CLI 0.31.0, so the copy you are reading can be older than
25
+ These instructions ship with xflow CLI 0.32.0, so the copy you are reading can be older than
26
26
  the CLI answering your commands.
27
27
 
28
28
  When the CLI says this file does not match it, run `xflow skills --refresh` and then **read
@@ -288,7 +288,8 @@ with the platform on every call, and the handler receives the answer in `event.x
288
288
  exports.handler = async (event) => {
289
289
  const { caller, user } = event.xflow
290
290
  // caller: 'visitor' (a person), 'service' (another function of this project),
291
- // 'external' (an outside service with a key), 'schedule' (a timer run)
291
+ // 'external' (an outside service with a key), 'schedule' (a timer run),
292
+ // 'public' (anyone, see below)
292
293
  // user: { id, role } for a visitor, null for everything else
293
294
  }
294
295
  ```
@@ -321,13 +322,30 @@ An outside service (a payment webhook, a bot, a CRM) has no person behind it and
321
322
  that one function. Keys are not issued by default and the CLI cannot create one: a human issues
322
323
  it in the project settings, «Облачные функции» → the function → «Настройки»; a standalone
323
324
  function has a screen of its own, «Функции» → the function → «Настройки». Ask the user to do
324
- that and to paste the address back — never invent another way in. Send it in the
325
- `X-Function-Key` header. A function holds at most two keys, the second one to replace the first
326
- without downtime, not to serve a second consumer.
325
+ that — never invent another way in. The service sends the key in the `X-Function-Key` header
326
+ to the address `xflow functions list` prints. A function holds at most two keys, the second
327
+ one to replace the first without downtime, not to serve a second consumer.
327
328
 
328
- `xflow functions list` shows who can reach each function: `in-app only` (no keys, answers
329
- only inside the application) or `external (N keys)` (a human issued external access). Key
330
- values are never shown there.
329
+ A function behind a public page (a form on a landing, a lookup, a calculator on
330
+ `xflowpage.ru`) has neither a person nor a key: every visitor calls it. Declare that in the
331
+ code and nothing else is needed, no key, no setting, nobody to ask:
332
+
333
+ ```js
334
+ exports.access = 'public'
335
+ ```
336
+
337
+ The wrapper then lets a call without any credential through, with `caller: 'public'` and
338
+ `user: null`, and never asks the platform. The page calls the address from `xflow functions
339
+ list` directly (CORS is open) and bakes no key into its files. Everything else stays as it
340
+ is: a call that does carry a pass or a key is still checked. Use it only for a function whose
341
+ work is fine for anyone on the internet to trigger: it cannot hold `minRole`, and it must not
342
+ write or delete data on the caller's word, there is no caller to trust. The platform marks
343
+ such a function «Открыта всем»
344
+ in the interface, and removing the line and deploying closes it again.
345
+
346
+ `xflow functions list` shows who can reach each function: `in-app only` (answers only inside
347
+ the application), `external (N keys)` (a human issued external access), `public` (the code
348
+ opened it), and the address of every deployed function. Key values are never shown there.
331
349
 
332
350
  ## Secrets and connected accounts
333
351
 
@@ -605,15 +623,17 @@ platform: pick a page when the audience is outside the organization.
605
623
  - Static files only: HTML, CSS, JS, images, fonts, PDF, audio, video. No server code, database
606
624
  or functions on a page. Upload what the build writes (`dist`), never a folder with
607
625
  `package.json`. At most 5 MB zipped, 25 MB unpacked, 1000 files.
626
+ - A page that needs a backend (a form, a lookup) calls a cloud function of a project that
627
+ declares `exports.access = 'public'` (see «Who is calling»): the page fetches the address
628
+ from `xflow functions list` directly, with no key and no header. The function lives in a
629
+ project, the page does not: deploy the function first, then upload the page.
608
630
  - Everything in a page is readable by every visitor. Never put a key, token or password into
609
- it: a known key format gets the upload refused, anything else simply leaks. A function key is
610
- the exception: a person issues it in the settings of the function, and a form on a page may
611
- call that function with it. So can every visitor.
631
+ it: a known key format gets the upload refused, anything else simply leaks.
612
632
  - Search engines are asked not to index pages: do not promise SEO.
613
633
  - The MCP `pages` tool uploads one self-contained HTML document up to 150 KB.
614
- - Pages take the key of the whole organization, the one `xflow login` issues. The section is in
615
- beta, switched on per organization by XFlow support: that refusal is not yours to fix. Switching
616
- a page off and deleting it are for a person, in the platform interface.
634
+ - Pages take the key of the whole organization, the one `xflow login` issues; a key scoped to
635
+ projects is refused, and that refusal is not yours to fix. Switching a page off and deleting it
636
+ are for a person, in the platform interface.
617
637
 
618
638
  ## Organizations and keys
619
639