sandflare-cli 2.0.26__tar.gz → 2.0.28__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.
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/PKG-INFO +1 -1
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/pyproject.toml +1 -1
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli/main.py +76 -1
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli.egg-info/PKG-INFO +1 -1
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/README.md +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli/__init__.py +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli.egg-info/SOURCES.txt +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli.egg-info/dependency_links.txt +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli.egg-info/entry_points.txt +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/sandflare_cli.egg-info/top_level.txt +0 -0
- {sandflare_cli-2.0.26 → sandflare_cli-2.0.28}/setup.cfg +0 -0
|
@@ -276,6 +276,62 @@ def sandbox_browser(args):
|
|
|
276
276
|
die(f"Unknown browser action: {action}. Valid: screenshot, navigate, text, html, elements, click, type, key, url, start")
|
|
277
277
|
|
|
278
278
|
|
|
279
|
+
# ── Database commands ─────────────────────────────────────────────────────────
|
|
280
|
+
|
|
281
|
+
def db_create(args):
|
|
282
|
+
body: dict = {}
|
|
283
|
+
if args.label:
|
|
284
|
+
body["label"] = args.label
|
|
285
|
+
if args.size:
|
|
286
|
+
body["size"] = args.size
|
|
287
|
+
result = api("POST", "/databases", body)
|
|
288
|
+
db_id = result.get("exec_id") or result.get("sandbox_id") or result.get("id", "")
|
|
289
|
+
label = result.get("label", "")
|
|
290
|
+
psql_url = result.get("psql_url", "")
|
|
291
|
+
ok(f"Database \033[1m{label or db_id}\033[0m created.")
|
|
292
|
+
if psql_url:
|
|
293
|
+
# Print masked URL for display, then the full one for scripting
|
|
294
|
+
masked = psql_url[:30] + "…" + psql_url[-20:] if len(psql_url) > 55 else psql_url
|
|
295
|
+
info(f"Connection: {masked}")
|
|
296
|
+
print(psql_url)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def db_list(_args):
|
|
300
|
+
result = api("GET", "/databases")
|
|
301
|
+
items = (result or {}).get("databases", [])
|
|
302
|
+
if not items:
|
|
303
|
+
info("No databases found.")
|
|
304
|
+
return
|
|
305
|
+
print_table(
|
|
306
|
+
["ID", "LABEL", "STATUS", "SIZE", "CREATED"],
|
|
307
|
+
[
|
|
308
|
+
[
|
|
309
|
+
(item.get("exec_id") or item.get("id") or "")[:18],
|
|
310
|
+
item.get("label", ""),
|
|
311
|
+
item.get("status", ""),
|
|
312
|
+
f"{item.get('memory_mb', 0) // 1024}GB" if item.get("memory_mb") else "",
|
|
313
|
+
(item.get("created_at", "") or "")[:10],
|
|
314
|
+
]
|
|
315
|
+
for item in items
|
|
316
|
+
],
|
|
317
|
+
[36, 20, 10, 6, 12],
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def db_delete(args):
|
|
322
|
+
api("DELETE", f"/databases/{args.id}")
|
|
323
|
+
ok(f"Database \033[1m{args.id}\033[0m deleted.")
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def db_url(args):
|
|
327
|
+
"""Print the raw psql connection URL — useful for piping to psql."""
|
|
328
|
+
result = api("GET", f"/databases/{args.id}")
|
|
329
|
+
url = result.get("psql_url", "")
|
|
330
|
+
if not url:
|
|
331
|
+
die("No psql_url in response. Database may still be starting.")
|
|
332
|
+
print(url)
|
|
333
|
+
|
|
334
|
+
|
|
279
335
|
def keys_list(_args):
|
|
280
336
|
result = api("GET", "/api-keys")
|
|
281
337
|
items = result if isinstance(result, list) else result.get("keys", [])
|
|
@@ -572,9 +628,28 @@ def main():
|
|
|
572
628
|
template_delete_parser.add_argument("id", help="Template ID (tpl-xxxxxxxx)")
|
|
573
629
|
template_delete_parser.set_defaults(func=template_delete)
|
|
574
630
|
|
|
631
|
+
db_parser = sub.add_parser("database", aliases=["db"], help="Manage persistent PostgreSQL databases")
|
|
632
|
+
db_sub = db_parser.add_subparsers(dest="action", metavar="<action>")
|
|
633
|
+
|
|
634
|
+
db_create_parser = db_sub.add_parser("create", help="Create a new database")
|
|
635
|
+
db_create_parser.add_argument("--label", "-l", help="Friendly label")
|
|
636
|
+
db_create_parser.add_argument("--size", "-s", default="nano", choices=["nano", "small", "medium"], help="Size (default: nano)")
|
|
637
|
+
db_create_parser.set_defaults(func=db_create)
|
|
638
|
+
|
|
639
|
+
db_list_parser = db_sub.add_parser("list", aliases=["ls"], help="List databases")
|
|
640
|
+
db_list_parser.set_defaults(func=db_list)
|
|
641
|
+
|
|
642
|
+
db_delete_parser = db_sub.add_parser("delete", aliases=["rm", "del"], help="Delete a database")
|
|
643
|
+
db_delete_parser.add_argument("id", help="Database ID")
|
|
644
|
+
db_delete_parser.set_defaults(func=db_delete)
|
|
645
|
+
|
|
646
|
+
db_url_parser = db_sub.add_parser("url", help="Print the psql connection URL")
|
|
647
|
+
db_url_parser.add_argument("id", help="Database ID")
|
|
648
|
+
db_url_parser.set_defaults(func=db_url)
|
|
649
|
+
|
|
575
650
|
args = parser.parse_args()
|
|
576
651
|
if not hasattr(args, "func"):
|
|
577
|
-
for subparser in [sandbox_parser, keys_parser, config_parser, template_parser]:
|
|
652
|
+
for subparser in [sandbox_parser, keys_parser, config_parser, template_parser, db_parser]:
|
|
578
653
|
if args.resource in (
|
|
579
654
|
getattr(subparser, "prog", "").split()[-1:] + list(subparser._option_string_actions.get("aliases", []))
|
|
580
655
|
):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|