extendvcc-cli 0.1.0__py3-none-any.whl

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.
extendvcc/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ """extendvcc — unofficial Extend virtual card client."""
2
+
3
+ from extendvcc.cards import (
4
+ activate_credit_card,
5
+ cancel_card,
6
+ close_card,
7
+ create_card,
8
+ create_cards_bulk,
9
+ enroll_credit_card,
10
+ get_card,
11
+ list_cards,
12
+ list_credit_cards,
13
+ list_issuers,
14
+ reconcile,
15
+ reveal_card,
16
+ update_card,
17
+ usage,
18
+ )
19
+ from extendvcc.models import CardStatus, CreditCard, Issuer, Recurrence, VirtualCard
20
+
21
+ __all__ = [
22
+ # models
23
+ "CardStatus",
24
+ "CreditCard",
25
+ "Issuer",
26
+ "Recurrence",
27
+ "VirtualCard",
28
+ # reads
29
+ "get_card",
30
+ "list_cards",
31
+ "list_credit_cards",
32
+ "list_issuers",
33
+ "usage",
34
+ # mutations
35
+ "cancel_card",
36
+ "close_card",
37
+ "create_card",
38
+ "create_cards_bulk",
39
+ "reconcile",
40
+ "update_card",
41
+ # reveal
42
+ "reveal_card",
43
+ # enroll
44
+ "activate_credit_card",
45
+ "enroll_credit_card",
46
+ ]
@@ -0,0 +1,24 @@
1
+ """Stable process exit codes for the extendvcc CLI.
2
+
3
+ These integers are part of the CLI's contract: scripts and CI pipelines can
4
+ branch on them. Map exceptions to codes in ``cli.main`` — do not invent new
5
+ codes ad hoc.
6
+
7
+ | Code | Name | Meaning |
8
+ |------|--------------------|------------------------------------------------------|
9
+ | 0 | EXIT_OK | Success. |
10
+ | 1 | EXIT_ERROR | Generic failure (library error, aborted confirm). |
11
+ | 2 | EXIT_USAGE | CLI input/usage error (bad flags, validation). |
12
+ | 3 | EXIT_AUTH_REQUIRED | Authentication needed or failed (login/OTP/session).|
13
+ | 4 | EXIT_DISABLED | Kill switch / account-risk: automation disabled. |
14
+ | 5 | EXIT_API_ERROR | Extend API returned an error response. |
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ EXIT_OK = 0
20
+ EXIT_ERROR = 1
21
+ EXIT_USAGE = 2
22
+ EXIT_AUTH_REQUIRED = 3
23
+ EXIT_DISABLED = 4
24
+ EXIT_API_ERROR = 5
extendvcc/_jsonl.py ADDED
@@ -0,0 +1,35 @@
1
+ """Vendored JSONL append helper."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+
9
+
10
+ def append_jsonl(path: Path, rows: list[dict], *, fsync: bool = False) -> None:
11
+ if not rows:
12
+ return
13
+ path.parent.mkdir(parents=True, exist_ok=True)
14
+ # Create the file owner-only (0600) regardless of umask. The ledger stores
15
+ # card ids/names/last4 — no PAN/CVC — but on shared machines a world-readable
16
+ # first write would still leak that local audit trail. Existing files are
17
+ # opened append-only and never have their mode altered.
18
+ is_new = not path.exists()
19
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
20
+ try:
21
+ if is_new:
22
+ # O_CREAT's mode is masked by umask; force 0600 so umask cannot widen it.
23
+ os.chmod(path, 0o600)
24
+ f = os.fdopen(fd, "a", encoding="utf-8")
25
+ except BaseException:
26
+ # os.fdopen/os.chmod failing leaves the raw fd open — close it before raising.
27
+ os.close(fd)
28
+ raise
29
+ with f:
30
+ for row in rows:
31
+ f.write(json.dumps(row, sort_keys=True, ensure_ascii=False))
32
+ f.write("\n")
33
+ if fsync:
34
+ f.flush()
35
+ os.fsync(f.fileno())
extendvcc/_paths.py ADDED
@@ -0,0 +1,28 @@
1
+ """Lazy path resolution with CLI override, env var, and default fallback."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+
8
+ _state_dir_override = None
9
+ _ledger_path_override = None
10
+
11
+
12
+ def configure(*, state_dir=None, ledger_path=None):
13
+ global _state_dir_override, _ledger_path_override
14
+ _state_dir_override = Path(state_dir) if state_dir else None
15
+ _ledger_path_override = Path(ledger_path) if ledger_path else None
16
+
17
+
18
+ def state_dir() -> Path:
19
+ return _state_dir_override or Path(os.environ.get("EXTENDVCC_STATE_DIR") or (Path.home() / ".config" / "extendvcc"))
20
+
21
+
22
+ def ledger_path() -> Path:
23
+ if _ledger_path_override:
24
+ return _ledger_path_override
25
+ env = os.environ.get("EXTENDVCC_LEDGER_PATH")
26
+ if env:
27
+ return Path(env)
28
+ return Path.home() / ".local" / "share" / "extendvcc" / "cards.jsonl"