reflex-hosting-cli 0.1.72a1__tar.gz → 0.2.0__tar.gz

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.
Files changed (40) hide show
  1. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/.gitignore +8 -1
  2. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/CHANGELOG.md +31 -1
  3. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/PKG-INFO +9 -2
  4. reflex_hosting_cli-0.2.0/pyproject.toml +55 -0
  5. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/hosting.py +3 -0
  6. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/console.py +83 -40
  7. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/dependency.py +2 -2
  8. reflex_hosting_cli-0.2.0/src/reflex_cli/utils/hosting.py +1873 -0
  9. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/apps.py +220 -302
  10. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/auth.py +1 -4
  11. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/cli.py +274 -151
  12. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/gcp.py +28 -49
  13. reflex_hosting_cli-0.2.0/src/reflex_cli/v2/project.py +434 -0
  14. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/providers.py +62 -78
  15. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/scan.py +27 -32
  16. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/secrets.py +33 -33
  17. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/vmtypes_regions.py +18 -7
  18. reflex_hosting_cli-0.1.72a1/pyproject.toml +0 -36
  19. reflex_hosting_cli-0.1.72a1/src/reflex_cli/utils/hosting.py +0 -3487
  20. reflex_hosting_cli-0.1.72a1/src/reflex_cli/v2/project.py +0 -492
  21. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/README.md +0 -0
  22. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/news/.gitkeep +0 -0
  23. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/__init__.py +0 -0
  24. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/cli.py +0 -0
  25. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/__init__.py +0 -0
  26. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/base.py +0 -0
  27. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/compiler.py +0 -0
  28. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/constants/log_level.py +0 -0
  29. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/core/__init__.py +0 -0
  30. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/core/config.py +0 -0
  31. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/deployments.py +0 -0
  32. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/__init__.py +0 -0
  33. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/cli_options.py +0 -0
  34. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/exceptions.py +0 -0
  35. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/log.py +0 -0
  36. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/utils/output.py +0 -0
  37. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/__init__.py +0 -0
  38. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/deploy.py +0 -0
  39. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/deployments.py +0 -0
  40. {reflex_hosting_cli-0.1.72a1 → reflex_hosting_cli-0.2.0}/src/reflex_cli/v2/utils.py +0 -0
@@ -7,7 +7,13 @@
7
7
  .mypy_cache/
8
8
  assets/external/*
9
9
  dist/*
10
- examples/
10
+ # Only the tracked examples; private apps under examples/ stay ignored. The
11
+ # pattern has a separator in the middle, so it is anchored to this directory
12
+ # and leaves the examples that live inside packages and tests alone.
13
+ examples/*
14
+ !examples/README.md
15
+ !examples/ruff.toml
16
+ !examples/playground/
11
17
  .web
12
18
  .states
13
19
  .idea
@@ -21,6 +27,7 @@ requirements.txt
21
27
  .pyi_generator_diff
22
28
  reflex.db
23
29
  .codspeed
30
+ .reflex-bench/
24
31
  .env
25
32
  .env.*
26
33
  node_modules
@@ -1,4 +1,34 @@
1
- ## v0.1.72a1 (2026-09-10)
1
+ ## v0.2.0 (2026-10-08)
2
+
3
+ ### Breaking Changes
4
+
5
+ - Some `reflex cloud` commands changed what they report: ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
6
+ - A refused request exits non-zero instead of printing a `"... failed: ..."` line and exiting 0, and `--json` writes no document. This includes `vmtypes` and `regions`, which answered a failed request with an empty listing, and `apps stop`, `apps start` and `apps delete`, which now report their own outcome rather than echoing the server's message.
7
+ - `apps history --json` replaces `hostname` with the deployment's `url`, reports `vm type` as the machine's name rather than an object, and reports `timestamp` as an ISO 8601 string with an offset. `apps inspect --json` drops `hostname` from `latest_deployment`.
8
+ - `create-token --json` replaces `expires_in_days` with `expires_at`, an ISO 8601 string or `null`, carrying the expiry the server applied.
9
+ - `apps logs` drops its unused `--cursor` option, and its `--json` document returns every line in the window rather than one page.
10
+ - `apps status --watch --json` reports `"success": null` when the watch stopped before the deployment finished.
11
+ - `project role-permissions` lists permission names rather than objects.
12
+ - `reflex deploy` requires a control plane that signs upload URLs; the multipart upload fallback for older ones, and its "payload is too large (over 100MB)" hint, are gone.
13
+ - Require Python 3.11 or newer; Python 3.10 is no longer supported. ([#7449](https://github.com/reflex-dev/reflex/issues/7449))
14
+
15
+ ### Bug Fixes
16
+
17
+ - `reflex cloud` reports a refusal as the sentence the API wrote rather than a message of its own, and an expired token now says to run `reflex login` wherever it turns up — not only where a command started by authenticating. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
18
+ - `reflex cloud apps delete` now exits non-zero when the app ID is not found. ([#7295](https://github.com/reflex-dev/reflex/issues/7295))
19
+ - With `--no-interactive`, a rejected access token now fails right away with the same message `reflex cloud whoami` gives, instead of starting the browser login. ([#7298](https://github.com/reflex-dev/reflex/issues/7298))
20
+ - Preserve a different stored access token when authentication rejects an outdated or explicitly supplied token. ([#7321](https://github.com/reflex-dev/reflex/issues/7321))
21
+ - `reflex deploy` now consistently shows the "Built with Reflex" badge on apps deployed on the free tier, including apps built with earlier reflex releases. Paid plans can still hide it with `show_built_with_reflex=False`. ([#7333](https://github.com/reflex-dev/reflex/issues/7333))
22
+ - `reflex cloud apps list`, `apps history` and `apps inspect` keep app names and app and deployment IDs whole on one line, so you can copy them from a normal-width terminal. `apps list` and `apps history` show fewer columns; `--json` still returns every field. `apps inspect` shows one field per row. Tables no longer draw cell borders. ([#7351](https://github.com/reflex-dev/reflex/issues/7351))
23
+ - `reflex cloud secrets update` now prints a success line naming the keys it set and whether the app is rebooting, like `secrets delete` already did. Only key names are printed; values are never logged. ([#7352](https://github.com/reflex-dev/reflex/issues/7352))
24
+ - Fail `reflex deploy` before building when an explicitly requested project does not exist or does not own the selected app. Accept equivalent UUID spellings, including uppercase and unhyphenated project IDs. ([#7355](https://github.com/reflex-dev/reflex/issues/7355))
25
+
26
+ ### Miscellaneous
27
+
28
+ - `reflex-hosting-cli` now talks to Reflex Build through `reflex-build-sdk`, so every command shares the SDK's retries, timeouts and typed errors. While the SDK is pre-1.0, the CLI pins it to a single patch line, so upgrade `reflex-hosting-cli` to move to a newer SDK rather than upgrading the SDK on its own. ([#7207](https://github.com/reflex-dev/reflex/issues/7207))
29
+
30
+
31
+ ## v0.1.72 (2026-09-11)
2
32
 
3
33
  ### Breaking Changes
4
34
 
@@ -1,15 +1,22 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: reflex-hosting-cli
3
- Version: 0.1.72a1
3
+ Version: 0.2.0
4
4
  Summary: Reflex Hosting CLI
5
5
  Author-email: Nikhil Rao <nikhil@reflex.dev>, Alek Petuskey <alek@reflex.dev>
6
6
  Maintainer-email: Simon Young <simon@reflex.dev>, Khaleel Al-Adhami <khaleel@reflex.dev>
7
7
  License: Apache-2.0
8
- Requires-Python: >=3.10
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Classifier: Programming Language :: Python :: 3.15
14
+ Requires-Python: >=3.11
9
15
  Requires-Dist: click>=8.2
10
16
  Requires-Dist: httpx<1.0,>=0.25.1
11
17
  Requires-Dist: packaging>=24.2
12
18
  Requires-Dist: platformdirs<5.0,>=3.10.0
19
+ Requires-Dist: reflex-build-sdk[httpx]!=0.1.1,<0.1.1.post,>=0.1.0
13
20
  Requires-Dist: rich<16,>=13
14
21
  Description-Content-Type: text/markdown
15
22
 
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "reflex-hosting-cli"
3
+ dynamic = ["version"]
4
+ description = "Reflex Hosting CLI"
5
+ license.text = "Apache-2.0"
6
+ readme = "README.md"
7
+ authors = [
8
+ { name = "Nikhil Rao", email = "nikhil@reflex.dev" },
9
+ { name = "Alek Petuskey", email = "alek@reflex.dev" },
10
+ ]
11
+ maintainers = [
12
+ { name = "Simon Young", email = "simon@reflex.dev" },
13
+ { name = "Khaleel Al-Adhami", email = "khaleel@reflex.dev" },
14
+ ]
15
+ requires-python = ">=3.11"
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ "Programming Language :: Python :: 3.15",
23
+ ]
24
+ dependencies = [
25
+ "click >=8.2",
26
+ # Imported directly by `check_version`, so it is declared here rather than
27
+ # taken on loan from reflex-build-sdk's own pin.
28
+ "httpx >=0.25.1,<1.0",
29
+ "packaging >=24.2",
30
+ "platformdirs >=3.10.0,<5.0",
31
+ # The SDK ships no HTTP library of its own; [httpx] points it at the one
32
+ # `check_version` already pulls in, so the extra costs nothing to install.
33
+ # The SDK is pre-1.0, so every release may break its API: cap at the patch
34
+ # and raise all three bounds when adopting a new one. The floor admits the
35
+ # workspace's dev build until the 0.1.0 alpha publishes and materialization
36
+ # lifts it; the cap admits 0.1.0 and the ``0.1.1.devN`` builds that follow
37
+ # its tag, but not 0.1.1 itself.
38
+ "reflex-build-sdk[httpx] >=0.1.0,<0.1.1.post,!=0.1.1",
39
+ "rich >=13,<16",
40
+ ]
41
+
42
+ [tool.hatch.version]
43
+ source = "uv-dynamic-versioning"
44
+
45
+ [tool.uv-dynamic-versioning]
46
+ pattern-prefix = "reflex-hosting-cli-"
47
+ fallback-version = "0.0.0dev0"
48
+ bump = true
49
+
50
+ [tool.hatch.build.targets.wheel]
51
+ packages = ["src/reflex_cli"]
52
+
53
+ [build-system]
54
+ requires = ["hatchling", "uv-dynamic-versioning"]
55
+ build-backend = "hatchling.build"
@@ -41,6 +41,9 @@ class Hosting(SimpleNamespace):
41
41
  # How long to wait between retry attempts
42
42
  AUTH_RETRY_SLEEP_DURATION = 5
43
43
 
44
+ # Tiers (lowercased) whose deploys may hide the "Built with Reflex" badge
45
+ PAID_TIERS = frozenset(("pro", "team", "enterprise"))
46
+
44
47
  # Aliases for compatibility with previous versions of Reflex
45
48
  CP_BACKEND_URL = HOSTING_SERVICE
46
49
  CP_WEB_URL = HOSTING_SERVICE_UI
@@ -7,37 +7,104 @@ prompts, tables, spinners and plain prints.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from collections.abc import Sequence
10
+ from collections.abc import Collection, Sequence
11
11
  from typing import overload
12
12
 
13
+ from rich import box
14
+ from rich.cells import cell_len
15
+ from rich.console import Console, OverflowMethod
16
+ from rich.table import Table
17
+
13
18
  from reflex_cli.constants.base import LogLevel
14
19
  from reflex_cli.utils.log import HAS_REFLEX_BASE, is_json_mode, is_stdout_reserved
15
20
  from reflex_cli.utils.log import set_log_level as _set_log_level
16
21
 
22
+ # The narrowest a folding table column gets before rows print as blocks.
23
+ _MIN_FOLD_WIDTH = 8
24
+
25
+ _console = Console(highlight=False)
26
+ _console_stderr = Console(stderr=True, highlight=False)
27
+
28
+
29
+ def _human_console() -> Console:
30
+ """Resolve the console human-readable output belongs on.
31
+
32
+ Returns:
33
+ The stderr console while stdout is carrying a machine-readable
34
+ document, and the stdout console otherwise.
35
+ """
36
+ return _console_stderr if is_stdout_reserved() else _console
37
+
38
+
39
+ def print_table(
40
+ tabular_data: list[list[str]],
41
+ headers: Sequence[str] = (),
42
+ overflow: OverflowMethod = "ellipsis",
43
+ no_wrap: Collection[str] = (),
44
+ ) -> None:
45
+ """Print a table to the console.
46
+
47
+ Args:
48
+ tabular_data: The data to print in tabular format.
49
+ headers: The headers for the table.
50
+ overflow: What to do with a cell too wide for its column. The default
51
+ cuts it short; pass "fold" for values a user has to read in full,
52
+ such as an email or an identifier.
53
+ no_wrap: Headers of the columns whose values stay on one line, so a
54
+ user can copy them. The other columns give up the width. When the
55
+ terminal is too narrow for that, each row prints as a block of
56
+ header and value lines instead, so no value is cut or squeezed.
57
+ """
58
+ if is_json_mode():
59
+ # Only reflex-base has a JSON mode. Pass just the arguments every
60
+ # reflex-base release accepts.
61
+ from reflex_base.utils.console import print_table as base_print_table
62
+
63
+ base_print_table(tabular_data, headers=headers)
64
+ return
65
+ console = _human_console()
66
+ # A no_wrap column needs its widest value; a folding column that much up to
67
+ # _MIN_FOLD_WIDTH, so it stays readable.
68
+ min_widths = []
69
+ for index, column in enumerate(headers):
70
+ # Rows may be shorter than headers; the table leaves their tail blank.
71
+ values = (cell_len(row[index]) for row in tabular_data if index < len(row))
72
+ widest = max(cell_len(column), max(values, default=0))
73
+ min_widths.append(widest if column in no_wrap else min(widest, _MIN_FOLD_WIDTH))
74
+ # Each column also takes 3 cells of padding and gap, plus 1 for the edge.
75
+ if tabular_data and sum(min_widths) + 3 * len(headers) + 1 > console.width:
76
+ label_width = max(map(cell_len, headers), default=0)
77
+ for row in tabular_data:
78
+ for column, value in zip(headers, row, strict=False):
79
+ console.print(
80
+ f"{column.ljust(label_width)} {value}",
81
+ markup=False,
82
+ soft_wrap=True,
83
+ )
84
+ console.print()
85
+ return
86
+ table = Table(box=box.SIMPLE_HEAD)
87
+
88
+ for column, min_width in zip(headers, min_widths, strict=True):
89
+ table.add_column(
90
+ column, overflow=overflow, no_wrap=column in no_wrap, min_width=min_width
91
+ )
92
+
93
+ for row in tabular_data:
94
+ table.add_row(*row)
95
+
96
+ console.print(table)
97
+
98
+
17
99
  if HAS_REFLEX_BASE:
18
100
  from reflex_base.utils.console import ask as ask
19
101
  from reflex_base.utils.console import print as print
20
- from reflex_base.utils.console import print_table as print_table
21
102
  from reflex_base.utils.console import progress as progress
22
103
  from reflex_base.utils.console import rule as rule
23
104
  from reflex_base.utils.console import status as status
24
105
  else:
25
- from rich.console import Console, OverflowMethod
26
106
  from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
27
107
  from rich.prompt import Prompt
28
- from rich.table import Table
29
-
30
- _console = Console(highlight=False)
31
- _console_stderr = Console(stderr=True, highlight=False)
32
-
33
- def _human_console() -> Console:
34
- """Resolve the console human-readable output belongs on.
35
-
36
- Returns:
37
- The stderr console while stdout is carrying a machine-readable
38
- document, and the stdout console otherwise.
39
- """
40
- return _console_stderr if is_stdout_reserved() else _console
41
108
 
42
109
  def print(msg: str, **kwargs):
43
110
  """Print a message.
@@ -48,30 +115,6 @@ else:
48
115
  """
49
116
  _human_console().print(msg, **kwargs)
50
117
 
51
- def print_table(
52
- tabular_data: list[list[str]],
53
- headers: Sequence[str] = (),
54
- overflow: OverflowMethod = "ellipsis",
55
- ) -> None:
56
- """Print a table to the console.
57
-
58
- Args:
59
- tabular_data: The data to print in tabular format.
60
- headers: The headers for the table.
61
- overflow: What to do with a cell too wide for its column. The
62
- default cuts it short; pass "fold" for values a user has to
63
- read in full, such as an email or an identifier.
64
- """
65
- table = Table()
66
-
67
- for column in headers:
68
- table.add_column(column, overflow=overflow)
69
-
70
- for row in tabular_data:
71
- table.add_row(*row)
72
-
73
- _human_console().print(table)
74
-
75
118
  def rule(title: str, **kwargs):
76
119
  """Print a horizontal rule with a title.
77
120
 
@@ -34,12 +34,12 @@ def detect_encoding(filename: Path) -> str | None:
34
34
  raise FileNotFoundError
35
35
 
36
36
  for encoding in [
37
- None if sys.version_info < (3, 10) else io.text_encoding(None),
37
+ io.text_encoding(None),
38
38
  "utf-8",
39
39
  ]:
40
40
  try:
41
41
  filename.read_text(encoding)
42
- except UnicodeDecodeError: # noqa: PERF203
42
+ except UnicodeDecodeError:
43
43
  continue
44
44
  except Exception:
45
45
  return None