edgebase-admin 0.1.3__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.
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ *.egg
11
+ .venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 melodysdreamj
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: edgebase-admin
3
+ Version: 0.1.3
4
+ Summary: Python admin SDK for EdgeBase service-key workloads
5
+ Author: EdgeBase Team
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: edgebase-core<0.2.0,>=0.1.3
10
+ Description-Content-Type: text/markdown
11
+
12
+ # edgebase-admin
13
+
14
+ Server-only Python admin SDK for EdgeBase.
15
+
16
+ Use `edgebase-admin` from trusted environments that hold a Service Key, such as backend APIs, cron jobs, workers, and operational tooling. It exposes admin auth, service-key database access, storage management, raw SQL, functions, analytics, push, and native Cloudflare resources.
17
+
18
+ If you want the unified package that also includes the higher-level `EdgeBaseServer` entry point and room helpers, install [`edgebase`](https://pypi.org/project/edgebase/) instead.
19
+
20
+ ## Documentation Map
21
+
22
+ Use this README for the fast overview, then jump into the docs when you need depth:
23
+
24
+ - [SDK Overview](https://edgebase.fun/docs/sdks)
25
+ Install commands and language matrix for all public SDKs
26
+ - [Admin SDK](https://edgebase.fun/docs/sdks/client-vs-server)
27
+ Service-key concepts, trust boundaries, and admin-only capabilities
28
+ - [Admin SDK Reference](https://edgebase.fun/docs/admin-sdk/reference)
29
+ Cross-language auth, database, storage, functions, and push examples
30
+ - [Admin User Management](https://edgebase.fun/docs/authentication/admin-users)
31
+ Create, update, delete, and manage users with the Service Key
32
+ - [Database Admin SDK](https://edgebase.fun/docs/database/admin-sdk)
33
+ Table queries, filters, pagination, batch writes, and raw SQL
34
+ - [Storage](https://edgebase.fun/docs/storage/upload-download)
35
+ Uploads, downloads, metadata, and signed URLs
36
+ - [Analytics Admin SDK](https://edgebase.fun/docs/analytics/admin-sdk)
37
+ Request metrics, event tracking, and event queries
38
+ - [Push Admin SDK](https://edgebase.fun/docs/push/admin-sdk)
39
+ Push send, topic broadcast, token inspection, and logs
40
+ - [Native Resources](https://edgebase.fun/docs/server/native-resources)
41
+ KV, D1, Vectorize, and other edge-native resources
42
+
43
+ ## For AI Coding Assistants
44
+
45
+ This package includes an `llms.txt` file for AI-assisted development.
46
+
47
+ Use it when you want an agent or code assistant to:
48
+
49
+ - use the right Python admin method signatures
50
+ - remember which surfaces are properties vs methods
51
+ - avoid copying JavaScript or Go API shapes into Python
52
+ - choose `edgebase-admin` instead of the broader `edgebase` package when only admin features are needed
53
+
54
+ You can find it:
55
+
56
+ - in this repository: [llms.txt](https://github.com/edge-base/edgebase/blob/main/packages/sdk/python/packages/admin/llms.txt)
57
+ - in your environment after install, inside the `edgebase_admin` package directory as `llms.txt`
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ pip install edgebase-admin
63
+ ```
64
+
65
+ ## Quick Start
66
+
67
+ ```python
68
+ import os
69
+
70
+ from edgebase_admin import create_admin_client
71
+
72
+ admin = create_admin_client(
73
+ "https://your-project.edgebase.fun",
74
+ service_key=os.environ["EDGEBASE_SERVICE_KEY"],
75
+ )
76
+
77
+ users = admin.admin_auth.list_users(limit=20)
78
+
79
+ posts = (
80
+ admin.db("shared")
81
+ .table("posts")
82
+ .where("published", "==", True)
83
+ .order_by("createdAt", "desc")
84
+ .limit(10)
85
+ .get_list()
86
+ )
87
+
88
+ rows = admin.sql(
89
+ "shared",
90
+ None,
91
+ "SELECT COUNT(*) AS total FROM posts WHERE published = ?",
92
+ [1],
93
+ )
94
+
95
+ bucket = admin.storage().bucket("avatars")
96
+ signed = bucket.create_signed_url("user-1.jpg", expires_in="1h")
97
+
98
+ print(len(users.get("users", [])), len(posts.items), rows, signed.url)
99
+ ```
100
+
101
+ ## Core API
102
+
103
+ - `AdminClient(base_url, service_key=...)`
104
+ Main admin entry point
105
+ - `create_admin_client(base_url, service_key=...)`
106
+ Convenience helper matching the public docs
107
+ - `admin.admin_auth`
108
+ Admin user management
109
+ - `admin.db(namespace="shared", instance_id=None).table(name)`
110
+ Service-key database access
111
+ - `admin.storage()`
112
+ Storage bucket access
113
+ - `admin.sql(namespace="shared", instance_id=None, query="", params=None)`
114
+ Raw SQL
115
+ - `admin.functions()`
116
+ Call app functions from trusted code
117
+ - `admin.analytics()`
118
+ Query request metrics and track custom events
119
+ - `admin.push()`
120
+ Send push notifications and inspect logs
121
+ - `admin.kv(namespace)`, `admin.d1(database)`, `admin.vector(index)` / `admin.vectorize(index)`
122
+ Native Cloudflare resources
123
+
124
+ ## Requirements
125
+
126
+ - Python `3.10+`
127
+ - `edgebase-core>=0.1.3,<0.2.0`
128
+ - A valid EdgeBase Service Key
@@ -0,0 +1,117 @@
1
+ # edgebase-admin
2
+
3
+ Server-only Python admin SDK for EdgeBase.
4
+
5
+ Use `edgebase-admin` from trusted environments that hold a Service Key, such as backend APIs, cron jobs, workers, and operational tooling. It exposes admin auth, service-key database access, storage management, raw SQL, functions, analytics, push, and native Cloudflare resources.
6
+
7
+ If you want the unified package that also includes the higher-level `EdgeBaseServer` entry point and room helpers, install [`edgebase`](https://pypi.org/project/edgebase/) instead.
8
+
9
+ ## Documentation Map
10
+
11
+ Use this README for the fast overview, then jump into the docs when you need depth:
12
+
13
+ - [SDK Overview](https://edgebase.fun/docs/sdks)
14
+ Install commands and language matrix for all public SDKs
15
+ - [Admin SDK](https://edgebase.fun/docs/sdks/client-vs-server)
16
+ Service-key concepts, trust boundaries, and admin-only capabilities
17
+ - [Admin SDK Reference](https://edgebase.fun/docs/admin-sdk/reference)
18
+ Cross-language auth, database, storage, functions, and push examples
19
+ - [Admin User Management](https://edgebase.fun/docs/authentication/admin-users)
20
+ Create, update, delete, and manage users with the Service Key
21
+ - [Database Admin SDK](https://edgebase.fun/docs/database/admin-sdk)
22
+ Table queries, filters, pagination, batch writes, and raw SQL
23
+ - [Storage](https://edgebase.fun/docs/storage/upload-download)
24
+ Uploads, downloads, metadata, and signed URLs
25
+ - [Analytics Admin SDK](https://edgebase.fun/docs/analytics/admin-sdk)
26
+ Request metrics, event tracking, and event queries
27
+ - [Push Admin SDK](https://edgebase.fun/docs/push/admin-sdk)
28
+ Push send, topic broadcast, token inspection, and logs
29
+ - [Native Resources](https://edgebase.fun/docs/server/native-resources)
30
+ KV, D1, Vectorize, and other edge-native resources
31
+
32
+ ## For AI Coding Assistants
33
+
34
+ This package includes an `llms.txt` file for AI-assisted development.
35
+
36
+ Use it when you want an agent or code assistant to:
37
+
38
+ - use the right Python admin method signatures
39
+ - remember which surfaces are properties vs methods
40
+ - avoid copying JavaScript or Go API shapes into Python
41
+ - choose `edgebase-admin` instead of the broader `edgebase` package when only admin features are needed
42
+
43
+ You can find it:
44
+
45
+ - in this repository: [llms.txt](https://github.com/edge-base/edgebase/blob/main/packages/sdk/python/packages/admin/llms.txt)
46
+ - in your environment after install, inside the `edgebase_admin` package directory as `llms.txt`
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install edgebase-admin
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ ```python
57
+ import os
58
+
59
+ from edgebase_admin import create_admin_client
60
+
61
+ admin = create_admin_client(
62
+ "https://your-project.edgebase.fun",
63
+ service_key=os.environ["EDGEBASE_SERVICE_KEY"],
64
+ )
65
+
66
+ users = admin.admin_auth.list_users(limit=20)
67
+
68
+ posts = (
69
+ admin.db("shared")
70
+ .table("posts")
71
+ .where("published", "==", True)
72
+ .order_by("createdAt", "desc")
73
+ .limit(10)
74
+ .get_list()
75
+ )
76
+
77
+ rows = admin.sql(
78
+ "shared",
79
+ None,
80
+ "SELECT COUNT(*) AS total FROM posts WHERE published = ?",
81
+ [1],
82
+ )
83
+
84
+ bucket = admin.storage().bucket("avatars")
85
+ signed = bucket.create_signed_url("user-1.jpg", expires_in="1h")
86
+
87
+ print(len(users.get("users", [])), len(posts.items), rows, signed.url)
88
+ ```
89
+
90
+ ## Core API
91
+
92
+ - `AdminClient(base_url, service_key=...)`
93
+ Main admin entry point
94
+ - `create_admin_client(base_url, service_key=...)`
95
+ Convenience helper matching the public docs
96
+ - `admin.admin_auth`
97
+ Admin user management
98
+ - `admin.db(namespace="shared", instance_id=None).table(name)`
99
+ Service-key database access
100
+ - `admin.storage()`
101
+ Storage bucket access
102
+ - `admin.sql(namespace="shared", instance_id=None, query="", params=None)`
103
+ Raw SQL
104
+ - `admin.functions()`
105
+ Call app functions from trusted code
106
+ - `admin.analytics()`
107
+ Query request metrics and track custom events
108
+ - `admin.push()`
109
+ Send push notifications and inspect logs
110
+ - `admin.kv(namespace)`, `admin.d1(database)`, `admin.vector(index)` / `admin.vectorize(index)`
111
+ Native Cloudflare resources
112
+
113
+ ## Requirements
114
+
115
+ - Python `3.10+`
116
+ - `edgebase-core>=0.1.3,<0.2.0`
117
+ - A valid EdgeBase Service Key
@@ -0,0 +1,170 @@
1
+ # edgebase-admin
2
+
3
+ Use this file as a quick-reference contract for AI coding assistants working with the `edgebase-admin` Python package.
4
+
5
+ ## Package Boundary
6
+
7
+ Use `edgebase-admin` for trusted, service-key-backed server workloads.
8
+
9
+ This package is the slim Python admin SDK. It is the right choice when you need admin auth, service-key database access, storage management, raw SQL, functions, analytics, push, or native Cloudflare resources without the broader `edgebase` package.
10
+
11
+ ## Source Of Truth
12
+
13
+ - Package README: https://github.com/edge-base/edgebase/blob/main/packages/sdk/python/packages/admin/README.md
14
+ - SDK overview: https://edgebase.fun/docs/sdks
15
+ - Admin SDK guide: https://edgebase.fun/docs/sdks/client-vs-server
16
+ - Admin SDK reference: https://edgebase.fun/docs/admin-sdk/reference
17
+ - Admin users: https://edgebase.fun/docs/authentication/admin-users
18
+ - Database admin SDK: https://edgebase.fun/docs/database/admin-sdk
19
+ - Storage: https://edgebase.fun/docs/storage/upload-download
20
+ - Analytics admin SDK: https://edgebase.fun/docs/analytics/admin-sdk
21
+ - Push admin SDK: https://edgebase.fun/docs/push/admin-sdk
22
+ - Native resources: https://edgebase.fun/docs/server/native-resources
23
+
24
+ If docs, snippets, and assumptions disagree, prefer the current package API over guessed patterns from another runtime.
25
+
26
+ ## Canonical Examples
27
+
28
+ ### Create an admin client
29
+
30
+ ```python
31
+ import os
32
+
33
+ from edgebase_admin import create_admin_client
34
+
35
+ admin = create_admin_client(
36
+ "https://your-project.edgebase.fun",
37
+ service_key=os.environ["EDGEBASE_SERVICE_KEY"],
38
+ )
39
+ ```
40
+
41
+ ### Query data
42
+
43
+ ```python
44
+ posts = (
45
+ admin.db("shared")
46
+ .table("posts")
47
+ .where("published", "==", True)
48
+ .order_by("createdAt", "desc")
49
+ .limit(20)
50
+ .get_list()
51
+ )
52
+ ```
53
+
54
+ ### Manage users
55
+
56
+ ```python
57
+ page = admin.admin_auth.list_users(limit=20)
58
+
59
+ user = admin.admin_auth.create_user(
60
+ "june@example.com",
61
+ "securePassword",
62
+ data={"displayName": "June", "role": "editor"},
63
+ )
64
+
65
+ admin.admin_auth.set_custom_claims(user["id"], {"plan": "pro"})
66
+ ```
67
+
68
+ ### Storage
69
+
70
+ ```python
71
+ bucket = admin.storage().bucket("avatars")
72
+
73
+ bucket.upload("user-1.jpg", file_bytes, content_type="image/jpeg")
74
+ signed = bucket.create_signed_url("user-1.jpg", expires_in="1h")
75
+ ```
76
+
77
+ ### Functions and analytics
78
+
79
+ ```python
80
+ result = admin.functions().post("jobs/send-welcome-email", {"userId": "user-123"})
81
+
82
+ admin.analytics().track(
83
+ "user_upgraded",
84
+ {"plan": "pro", "amount": 29.99},
85
+ user_id="user_123",
86
+ )
87
+ ```
88
+
89
+ ### Native resources
90
+
91
+ ```python
92
+ admin.kv("cache").set("homepage", "ready", ttl=300)
93
+ rows = admin.d1("analytics").query("SELECT 1", [])
94
+ matches = admin.vector("embeddings").search([0.1, 0.2, 0.3], top_k=5)
95
+ ```
96
+
97
+ ## Common Mistakes
98
+
99
+ - use `create_admin_client(...)` or `AdminClient(...)`, not a browser/client SDK factory
100
+ - `admin.admin_auth` is a property, not a method
101
+ - `admin.storage()`, `admin.functions()`, `admin.analytics()`, and `admin.push()` are methods
102
+ - `admin.db(namespace="shared", instance_id=None)` uses an optional positional instance id
103
+ - `table.get()` returns `ListResult`, not a single record
104
+ - use `table.get_one(id)` or `table.doc(id).get()` for a single record
105
+ - `AdminClient.sql(...)` requires a non-empty query string
106
+ - `admin.admin_auth.create_user(...)` accepts optional profile fields via `data=...`
107
+ - `create_signed_upload_url(path, expires_in=...)` expects seconds as an `int`
108
+ - `admin.vector(...)` and `admin.vectorize(...)` are both valid; `vectorize()` is just an alias
109
+
110
+ ## Quick Reference
111
+
112
+ ```python
113
+ # Initialize
114
+ admin = create_admin_client(base_url, service_key=service_key)
115
+
116
+ # Admin auth (property)
117
+ admin.admin_auth.get_user(user_id) # dict
118
+ admin.admin_auth.create_user(email, password, data=None) # dict
119
+ admin.admin_auth.update_user(user_id, data) # dict
120
+ admin.admin_auth.delete_user(user_id) # dict
121
+ admin.admin_auth.list_users(limit=20, cursor=None) # dict
122
+ admin.admin_auth.set_custom_claims(user_id, claims) # None
123
+ admin.admin_auth.revoke_all_sessions(user_id) # None
124
+ admin.admin_auth.disable_mfa(user_id) # None
125
+
126
+ # Database
127
+ admin.db("shared").table("posts").get_list() # ListResult
128
+ admin.db("shared").table("posts").get_one("id-1") # dict
129
+ admin.db("shared").table("posts").insert(record) # dict
130
+ admin.db("shared").table("posts").update("id-1", data) # dict
131
+ admin.db("shared").table("posts").delete("id-1") # dict
132
+ admin.sql("shared", None, query, params) # list
133
+
134
+ # Storage
135
+ bucket = admin.storage().bucket("avatars")
136
+ bucket.get_url("user-1.jpg") # str
137
+ bucket.upload("user-1.jpg", file_bytes, content_type="image/jpeg") # dict
138
+ bucket.download("user-1.jpg") # bytes
139
+ bucket.get_metadata("user-1.jpg") # FileInfo
140
+ bucket.update_metadata("user-1.jpg", metadata) # dict
141
+ bucket.list(prefix="", limit=100, offset=0) # list[FileInfo]
142
+ bucket.list_page(prefix="", limit=100, cursor=None) # FileListResult
143
+ bucket.create_signed_url("user-1.jpg", expires_in="1h") # SignedUrlResult
144
+ bucket.create_signed_upload_url("large.zip", expires_in=600) # SignedUrlResult
145
+
146
+ # Functions / analytics / push
147
+ admin.functions().get("health", query=None) # Any
148
+ admin.functions().post("jobs/run", body={}) # Any
149
+ admin.analytics().overview(range="7d") # dict
150
+ admin.analytics().track(name, properties=None, user_id=None) # None
151
+ admin.analytics().track_batch(events) # None
152
+ admin.analytics().query_events(metric="list", range="7d") # Any
153
+ admin.push().send(user_id, payload) # dict
154
+ admin.push().send_many(user_ids, payload) # dict
155
+ admin.push().send_to_token(token, payload, platform=None) # dict
156
+ admin.push().send_to_topic(topic, payload) # dict
157
+ admin.push().broadcast(payload) # dict
158
+ admin.push().get_tokens(user_id) # list[dict]
159
+ admin.push().get_logs(user_id, limit=None) # list[dict]
160
+
161
+ # Native resources
162
+ admin.kv("cache").get("key") # str | None
163
+ admin.kv("cache").set("key", "value", ttl=300) # None
164
+ admin.kv("cache").list(prefix=None, limit=None, cursor=None) # dict
165
+ admin.kv("cache").delete("key") # None
166
+ admin.d1("analytics").exec("SELECT 1", []) # list
167
+ admin.d1("analytics").query("SELECT 1", []) # list
168
+ admin.vector("embeddings").search([0.1, 0.2], top_k=5) # list[dict]
169
+ admin.vectorize("embeddings").search([0.1, 0.2], top_k=5) # list[dict]
170
+ ```
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "edgebase-admin"
7
+ version = "0.1.3"
8
+ description = "Python admin SDK for EdgeBase service-key workloads"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "EdgeBase Team" }
14
+ ]
15
+ dependencies = ["edgebase-core>=0.1.3,<0.2.0"]
16
+
17
+ [tool.hatch.build.targets.sdist]
18
+ include = ["src/edgebase_admin", "README.md", "llms.txt"]
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/edgebase_admin"]
22
+
23
+ [tool.hatch.build.targets.wheel.force-include]
24
+ "llms.txt" = "edgebase_admin/llms.txt"
@@ -0,0 +1,23 @@
1
+ """EdgeBase Admin SDK — admin auth, KV, D1, Vectorize."""
2
+
3
+ from edgebase_admin.admin_auth import AdminAuthClient
4
+ from edgebase_admin.analytics import AnalyticsClient
5
+ from edgebase_admin.admin_client import AdminClient, DbRef, create_admin_client
6
+ from edgebase_admin.kv import KvClient
7
+ from edgebase_admin.d1 import D1Client
8
+ from edgebase_admin.functions import FunctionsClient
9
+ from edgebase_admin.vectorize import VectorizeClient
10
+ from edgebase_admin.push import PushClient
11
+
12
+ __all__ = [
13
+ "AdminAuthClient",
14
+ "AnalyticsClient",
15
+ "AdminClient",
16
+ "DbRef",
17
+ "create_admin_client",
18
+ "KvClient",
19
+ "D1Client",
20
+ "FunctionsClient",
21
+ "VectorizeClient",
22
+ "PushClient",
23
+ ]
@@ -0,0 +1,137 @@
1
+ """Admin authentication client — Service Key-based user management.
2
+
3
+ Python SDK is server-only: AdminAuthClient validates the service key is present
4
+ before making any request. Without a service key the server always returns 403,
5
+ so we short-circuit locally to save a round-trip and give a clear error.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+
12
+ from edgebase_core.errors import EdgeBaseError
13
+ from edgebase_core.http_client import HttpClient
14
+
15
+
16
+ class AdminAuthClient:
17
+ """Admin auth — server-side user management via Service Key.
18
+
19
+ Usage::
20
+
21
+ user = admin.admin_auth.get_user("user-id")
22
+ new_user = admin.admin_auth.create_user(
23
+ email="admin@example.com", password="secure"
24
+ )
25
+ admin.admin_auth.set_custom_claims("user-id", {"role": "pro"})
26
+ admin.admin_auth.revoke_all_sessions("user-id")
27
+ """
28
+
29
+ def __init__(self, client: HttpClient) -> None:
30
+ self._client = client
31
+
32
+ # ── Guard ─────────────────────────────────────────────────────────────────
33
+
34
+ def _require_service_key(self) -> None:
35
+ """Raise EdgeBaseError(403) locally if no service key is configured.
36
+
37
+ All admin operations require a service key.
38
+ Failing fast here avoids an unnecessary network round-trip and surfaces
39
+ the misconfiguration immediately with a clear error message.
40
+ """
41
+ if not getattr(self._client, "_service_key", None):
42
+ raise EdgeBaseError(
43
+ status_code=403,
44
+ message="Service Key required for admin operations. "
45
+ "Pass service_key= when constructing EdgeBaseServer.",
46
+ )
47
+
48
+ @staticmethod
49
+ def _unwrap_user_payload(payload: dict[str, Any]) -> dict[str, Any]:
50
+ user = payload.get("user")
51
+ if isinstance(user, dict):
52
+ merged = dict(user)
53
+ for key, value in payload.items():
54
+ if key != "user" and key not in merged:
55
+ merged[key] = value
56
+ return merged
57
+ return payload
58
+
59
+ # ── Public API ────────────────────────────────────────────────────────────
60
+
61
+ def get_user(self, user_id: str) -> dict[str, Any]:
62
+ """Get a user by ID."""
63
+ self._require_service_key()
64
+ result = self._client.get(f"/auth/admin/users/{user_id}")
65
+ return self._unwrap_user_payload(result if isinstance(result, dict) else {})
66
+
67
+ def create_user(
68
+ self,
69
+ email: str,
70
+ password: str,
71
+ data: dict[str, Any] | None = None,
72
+ ) -> dict[str, Any]:
73
+ """Create a new user."""
74
+ self._require_service_key()
75
+ body: dict[str, Any] = {"email": email, "password": password}
76
+ if data:
77
+ body["data"] = data
78
+ result = self._client.post("/auth/admin/users", body)
79
+ return self._unwrap_user_payload(result if isinstance(result, dict) else {})
80
+
81
+ def update_user(self, user_id: str, data: dict[str, Any]) -> dict[str, Any]:
82
+ """Update a user."""
83
+ self._require_service_key()
84
+ result = self._client.patch(f"/auth/admin/users/{user_id}", data)
85
+ return self._unwrap_user_payload(result if isinstance(result, dict) else {})
86
+
87
+ def delete_user(self, user_id: str) -> dict[str, Any]:
88
+ """Delete a user."""
89
+ self._require_service_key()
90
+ return self._client.delete(f"/auth/admin/users/{user_id}")
91
+
92
+ def list_users(
93
+ self,
94
+ limit: int = 20,
95
+ cursor: str | None = None,
96
+ ) -> dict[str, Any]:
97
+ """List users with cursor-based pagination.
98
+
99
+ Args:
100
+ limit: Maximum number of users to return (default 20).
101
+ cursor: Pagination cursor from previous response.
102
+
103
+ Returns:
104
+ Dict with 'users' list and optional 'cursor' for next page.
105
+ """
106
+ self._require_service_key()
107
+ params: dict[str, str] = {"limit": str(limit)}
108
+ if cursor:
109
+ params["cursor"] = cursor
110
+ result = self._client.get("/auth/admin/users", params)
111
+ return result if isinstance(result, dict) else {"users": [], "cursor": None}
112
+
113
+ def set_custom_claims(
114
+ self,
115
+ user_id: str,
116
+ claims: dict[str, Any],
117
+ ) -> None:
118
+ """Set custom claims for a user (reflected in JWT on next token refresh)."""
119
+ self._require_service_key()
120
+ self._client.put(f"/auth/admin/users/{user_id}/claims", claims)
121
+
122
+ def revoke_all_sessions(self, user_id: str) -> None:
123
+ """Revoke all sessions for a user (force re-authentication)."""
124
+ self._require_service_key()
125
+ self._client.post(f"/auth/admin/users/{user_id}/revoke")
126
+
127
+ def disable_mfa(self, user_id: str) -> None:
128
+ """Disable MFA for a user (admin operation via Service Key).
129
+
130
+ Removes all MFA factors for the specified user, allowing them
131
+ to sign in without MFA verification.
132
+
133
+ Args:
134
+ user_id: The user's ID whose MFA should be disabled.
135
+ """
136
+ self._require_service_key()
137
+ self._client.delete(f"/auth/admin/users/{user_id}/mfa")