agentic-fabriq-sdk 0.1.14__py3-none-any.whl → 0.1.16__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.
Potentially problematic release.
This version of agentic-fabriq-sdk might be problematic. Click here for more details.
- af_cli/commands/agents.py +18 -18
- af_cli/commands/applications.py +323 -0
- af_cli/commands/auth.py +0 -6
- af_cli/commands/config.py +1 -1
- af_cli/commands/mcp_servers.py +5 -5
- af_cli/commands/secrets.py +6 -6
- af_cli/commands/tools.py +163 -89
- af_cli/main.py +2 -7
- af_sdk/__init__.py +15 -0
- af_sdk/auth/__init__.py +16 -0
- af_sdk/auth/application.py +264 -0
- af_sdk/auth/applications.py +264 -0
- af_sdk/fabriq_client.py +54 -1
- {agentic_fabriq_sdk-0.1.14.dist-info → agentic_fabriq_sdk-0.1.16.dist-info}/METADATA +14 -3
- {agentic_fabriq_sdk-0.1.14.dist-info → agentic_fabriq_sdk-0.1.16.dist-info}/RECORD +17 -14
- {agentic_fabriq_sdk-0.1.14.dist-info → agentic_fabriq_sdk-0.1.16.dist-info}/WHEEL +0 -0
- {agentic_fabriq_sdk-0.1.14.dist-info → agentic_fabriq_sdk-0.1.16.dist-info}/entry_points.txt +0 -0
af_cli/commands/tools.py
CHANGED
|
@@ -13,7 +13,7 @@ app = typer.Typer(help="Tool management commands")
|
|
|
13
13
|
|
|
14
14
|
@app.command()
|
|
15
15
|
def list(
|
|
16
|
-
format: str = typer.Option("table", "--format",
|
|
16
|
+
format: str = typer.Option("table", "--format", help="Output format"),
|
|
17
17
|
):
|
|
18
18
|
"""List your tool connections (configured and connected tools)."""
|
|
19
19
|
try:
|
|
@@ -56,7 +56,7 @@ def list(
|
|
|
56
56
|
@app.command()
|
|
57
57
|
def get(
|
|
58
58
|
connection_id: str = typer.Argument(..., help="Connection ID (e.g., 'google', 'slack')"),
|
|
59
|
-
format: str = typer.Option("table", "--format",
|
|
59
|
+
format: str = typer.Option("table", "--format", help="Output format"),
|
|
60
60
|
):
|
|
61
61
|
"""Get tool connection details."""
|
|
62
62
|
try:
|
|
@@ -121,24 +121,98 @@ def get(
|
|
|
121
121
|
|
|
122
122
|
@app.command()
|
|
123
123
|
def invoke(
|
|
124
|
-
|
|
125
|
-
method: str = typer.Option(..., "--method",
|
|
126
|
-
|
|
124
|
+
tool_identifier: str = typer.Argument(..., help="Tool name (e.g., 'slack') or UUID"),
|
|
125
|
+
method: str = typer.Option(..., "--method", help="Tool method to invoke"),
|
|
126
|
+
params: str = typer.Option(None, "--params", help="JSON string of method parameters (e.g., '{\"channel\": \"test\", \"text\": \"Hello\"}')"),
|
|
127
|
+
format: str = typer.Option("json", "--format", help="Output format (json, table, yaml)"),
|
|
127
128
|
):
|
|
128
|
-
"""Invoke a tool.
|
|
129
|
+
"""Invoke a tool by name or UUID.
|
|
130
|
+
|
|
131
|
+
Examples:
|
|
132
|
+
afctl tools invoke slack --method get_channels
|
|
133
|
+
afctl tools invoke slack --method post_message --params '{"channel": "test", "text": "Hello!"}'
|
|
134
|
+
afctl tools invoke c17b55af-18f8-49be-b9e9-44b1d1be429e --method get_channels
|
|
135
|
+
"""
|
|
129
136
|
try:
|
|
137
|
+
# Parse parameters if provided
|
|
138
|
+
parameters = {}
|
|
139
|
+
if params:
|
|
140
|
+
import json as json_lib
|
|
141
|
+
try:
|
|
142
|
+
parameters = json_lib.loads(params)
|
|
143
|
+
except json_lib.JSONDecodeError as e:
|
|
144
|
+
error(f"Invalid JSON in --params: {e}")
|
|
145
|
+
raise typer.Exit(1)
|
|
146
|
+
|
|
130
147
|
with get_client() as client:
|
|
148
|
+
# Try to resolve tool name to UUID if not already a UUID
|
|
149
|
+
tool_id = tool_identifier
|
|
150
|
+
try:
|
|
151
|
+
from uuid import UUID
|
|
152
|
+
UUID(tool_identifier)
|
|
153
|
+
# It's already a UUID, use it directly
|
|
154
|
+
except ValueError:
|
|
155
|
+
# Not a UUID, try to look up by name
|
|
156
|
+
info(f"Looking up tool '{tool_identifier}'...")
|
|
157
|
+
try:
|
|
158
|
+
tools_response = client.get("/api/v1/tools")
|
|
159
|
+
|
|
160
|
+
# Handle different response formats
|
|
161
|
+
if isinstance(tools_response, dict) and "tools" in tools_response:
|
|
162
|
+
tools = tools_response["tools"]
|
|
163
|
+
elif isinstance(tools_response, dict) and "items" in tools_response:
|
|
164
|
+
tools = tools_response["items"]
|
|
165
|
+
elif hasattr(tools_response, '__iter__') and not isinstance(tools_response, (str, dict)):
|
|
166
|
+
tools = list(tools_response)
|
|
167
|
+
else:
|
|
168
|
+
tools = []
|
|
169
|
+
|
|
170
|
+
# Find tool by name (case-insensitive)
|
|
171
|
+
matching_tools = [t for t in tools if isinstance(t, dict) and t.get("name", "").lower() == tool_identifier.lower()]
|
|
172
|
+
|
|
173
|
+
if not matching_tools:
|
|
174
|
+
error(f"Tool '{tool_identifier}' not found. Available tools:")
|
|
175
|
+
for t in tools:
|
|
176
|
+
if isinstance(t, dict):
|
|
177
|
+
print(f" - {t.get('name')} (ID: {t.get('id')})")
|
|
178
|
+
raise typer.Exit(1)
|
|
179
|
+
|
|
180
|
+
if len(matching_tools) > 1:
|
|
181
|
+
error(f"Multiple tools found with name '{tool_identifier}':")
|
|
182
|
+
for t in matching_tools:
|
|
183
|
+
print(f" - {t.get('name')} (ID: {t.get('id')})")
|
|
184
|
+
error("Please use the UUID instead.")
|
|
185
|
+
raise typer.Exit(1)
|
|
186
|
+
|
|
187
|
+
tool_id = matching_tools[0].get("id")
|
|
188
|
+
info(f"Resolved '{tool_identifier}' to tool ID: {tool_id}")
|
|
189
|
+
except Exception as lookup_error:
|
|
190
|
+
error(f"Failed to look up tool: {lookup_error}")
|
|
191
|
+
raise typer.Exit(1)
|
|
192
|
+
|
|
131
193
|
data = {
|
|
132
194
|
"method": method,
|
|
133
|
-
"parameters":
|
|
195
|
+
"parameters": parameters,
|
|
134
196
|
"context": {},
|
|
135
197
|
}
|
|
136
198
|
|
|
137
|
-
info(f"Invoking tool {
|
|
199
|
+
info(f"Invoking tool {tool_identifier} method {method}...")
|
|
138
200
|
response = client.post(f"/api/v1/tools/{tool_id}/invoke", data)
|
|
139
201
|
|
|
140
202
|
success("Tool invoked successfully")
|
|
141
|
-
|
|
203
|
+
|
|
204
|
+
# For tool invocations, show the result in a more readable format
|
|
205
|
+
if format == "json":
|
|
206
|
+
import json as json_lib
|
|
207
|
+
print(json_lib.dumps(response, indent=2))
|
|
208
|
+
elif format == "yaml":
|
|
209
|
+
import yaml
|
|
210
|
+
print(yaml.dump(response, default_flow_style=False))
|
|
211
|
+
else:
|
|
212
|
+
# For table format, show just the result field nicely
|
|
213
|
+
result = response.get("result", {})
|
|
214
|
+
print("\n📊 Result:")
|
|
215
|
+
print_output(result, format_type="json")
|
|
142
216
|
|
|
143
217
|
except Exception as e:
|
|
144
218
|
error(f"Failed to invoke tool: {e}")
|
|
@@ -150,30 +224,28 @@ def add(
|
|
|
150
224
|
tool: str = typer.Argument(..., help="Tool name (google_drive, google_slides, slack, notion, github, etc.)"),
|
|
151
225
|
connection_id: str = typer.Option(..., "--connection-id", help="Unique connection ID"),
|
|
152
226
|
display_name: str = typer.Option(None, "--display-name", help="Human-readable name"),
|
|
153
|
-
method: str = typer.Option(..., "--method", help="Connection method: '
|
|
154
|
-
|
|
155
|
-
# API method fields
|
|
156
|
-
token: str = typer.Option(None, "--token", help="API token (for api method)"),
|
|
227
|
+
method: str = typer.Option(..., "--method", help="Connection method: 'api_credentials' or 'oauth'"),
|
|
157
228
|
|
|
158
|
-
#
|
|
159
|
-
|
|
160
|
-
|
|
229
|
+
# API credentials method fields (can be either a token OR client_id/secret)
|
|
230
|
+
token: str = typer.Option(None, "--token", help="API token (for simple token-based auth like Notion, Slack bot)"),
|
|
231
|
+
client_id: str = typer.Option(None, "--client-id", help="OAuth client ID (for app-based auth like Google, Slack)"),
|
|
232
|
+
client_secret: str = typer.Option(None, "--client-secret", help="OAuth client secret (for app-based auth)"),
|
|
161
233
|
redirect_uri: str = typer.Option(None, "--redirect-uri", help="OAuth redirect URI (optional, auto-generated)"),
|
|
162
234
|
):
|
|
163
235
|
"""
|
|
164
236
|
Add a new tool connection with credentials.
|
|
165
237
|
|
|
166
238
|
Examples:
|
|
167
|
-
# Notion (
|
|
168
|
-
afctl tools add notion --connection-id notion-work --method
|
|
239
|
+
# Notion (api_credentials method - single token)
|
|
240
|
+
afctl tools add notion --connection-id notion-work --method api_credentials --token "secret_abc123"
|
|
169
241
|
|
|
170
|
-
# Google (
|
|
171
|
-
afctl tools add
|
|
242
|
+
# Google (api_credentials method - OAuth app)
|
|
243
|
+
afctl tools add google_drive --connection-id google-work --method api_credentials \\
|
|
172
244
|
--client-id "123.apps.googleusercontent.com" \\
|
|
173
245
|
--client-secret "GOCSPX-abc123"
|
|
174
246
|
|
|
175
|
-
# Slack bot (
|
|
176
|
-
afctl tools add slack --connection-id slack-bot --method
|
|
247
|
+
# Slack bot (api_credentials method - single token)
|
|
248
|
+
afctl tools add slack --connection-id slack-bot --method api_credentials --token "xoxb-123..."
|
|
177
249
|
"""
|
|
178
250
|
try:
|
|
179
251
|
from af_cli.core.config import get_config
|
|
@@ -202,23 +274,24 @@ def add(
|
|
|
202
274
|
raise typer.Exit(1)
|
|
203
275
|
|
|
204
276
|
# Validate method
|
|
205
|
-
if method not in ["
|
|
206
|
-
error("Method must be '
|
|
277
|
+
if method not in ["api_credentials", "oauth"]:
|
|
278
|
+
error("Method must be 'api_credentials' or 'oauth'")
|
|
207
279
|
raise typer.Exit(1)
|
|
208
280
|
|
|
209
|
-
# Validate
|
|
210
|
-
if method == "
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
info(f"
|
|
221
|
-
info(f" --
|
|
281
|
+
# Validate api_credentials method requirements
|
|
282
|
+
if method == "api_credentials":
|
|
283
|
+
# Must have either token OR (client_id + client_secret)
|
|
284
|
+
has_token = bool(token)
|
|
285
|
+
has_oauth_creds = bool(client_id and client_secret)
|
|
286
|
+
|
|
287
|
+
if not has_token and not has_oauth_creds:
|
|
288
|
+
error("api_credentials method requires either:")
|
|
289
|
+
info(" • --token (for simple token auth like Notion, Slack bot)")
|
|
290
|
+
info(" • --client-id and --client-secret (for OAuth app auth like Google)")
|
|
291
|
+
info("")
|
|
292
|
+
info(f"Examples:")
|
|
293
|
+
info(f" afctl tools add {tool} --connection-id {connection_id} --method api_credentials --token YOUR_TOKEN")
|
|
294
|
+
info(f" afctl tools add {tool} --connection-id {connection_id} --method api_credentials --client-id ID --client-secret SECRET")
|
|
222
295
|
raise typer.Exit(1)
|
|
223
296
|
|
|
224
297
|
info(f"Creating connection: {connection_id}")
|
|
@@ -236,51 +309,59 @@ def add(
|
|
|
236
309
|
client.post("/api/v1/user-connections", data=connection_data)
|
|
237
310
|
success(f"✅ Connection entry created: {connection_id}")
|
|
238
311
|
|
|
239
|
-
# Step 2: Store credentials based on
|
|
240
|
-
if method == "
|
|
312
|
+
# Step 2: Store credentials based on what was provided
|
|
313
|
+
if method == "api_credentials":
|
|
241
314
|
# Determine the API base tool name (Google tools all use "google")
|
|
242
315
|
api_tool_name = "google" if (tool.startswith("google_") or tool == "gmail") else tool
|
|
243
316
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
f"
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
317
|
+
if token:
|
|
318
|
+
# Simple token-based auth (Notion, Slack bot, etc.)
|
|
319
|
+
info("Storing API token...")
|
|
320
|
+
|
|
321
|
+
# Tool-specific endpoint and payload mappings
|
|
322
|
+
if tool == "notion":
|
|
323
|
+
# Notion uses /config endpoint with integration_token field
|
|
324
|
+
endpoint = f"/api/v1/tools/{tool}/config?connection_id={connection_id}"
|
|
325
|
+
cred_payload = {"integration_token": token}
|
|
326
|
+
else:
|
|
327
|
+
# Generic tools use /connection endpoint with api_token field
|
|
328
|
+
endpoint = f"/api/v1/tools/{tool}/connection?connection_id={connection_id}"
|
|
329
|
+
cred_payload = {"api_token": token}
|
|
330
|
+
|
|
331
|
+
client.post(endpoint, data=cred_payload)
|
|
332
|
+
success("✅ API token stored")
|
|
333
|
+
success(f"✅ Connection '{connection_id}' is ready to use!")
|
|
334
|
+
|
|
335
|
+
elif client_id and client_secret:
|
|
336
|
+
# OAuth app credentials (Google, Slack app, etc.)
|
|
337
|
+
# Auto-generate redirect_uri if not provided
|
|
338
|
+
if not redirect_uri:
|
|
339
|
+
config = get_config()
|
|
340
|
+
redirect_uri = f"{config.gateway_url}/api/v1/tools/{api_tool_name}/oauth/callback"
|
|
341
|
+
info(f"Using default redirect URI: {redirect_uri}")
|
|
342
|
+
|
|
343
|
+
# Store OAuth app config
|
|
344
|
+
info("Storing OAuth app credentials...")
|
|
345
|
+
config_payload = {
|
|
346
|
+
"client_id": client_id,
|
|
347
|
+
"client_secret": client_secret,
|
|
348
|
+
}
|
|
349
|
+
if redirect_uri:
|
|
350
|
+
config_payload["redirect_uri"] = redirect_uri
|
|
351
|
+
|
|
352
|
+
client.post(
|
|
353
|
+
f"/api/v1/tools/{api_tool_name}/config?connection_id={connection_id}",
|
|
354
|
+
data=config_payload
|
|
355
|
+
)
|
|
356
|
+
success("✅ OAuth app credentials stored")
|
|
357
|
+
info("")
|
|
358
|
+
info(f"Next: Run 'afctl tools connect {connection_id}' to complete OAuth setup")
|
|
359
|
+
|
|
360
|
+
elif method == "oauth":
|
|
361
|
+
# OAuth flow (legacy, redirect to api_credentials)
|
|
362
|
+
error("The 'oauth' method is deprecated. Please use 'api_credentials' instead.")
|
|
363
|
+
info("All credential storage now uses the 'api_credentials' method.")
|
|
364
|
+
raise typer.Exit(1)
|
|
284
365
|
|
|
285
366
|
# Show helpful info
|
|
286
367
|
info("")
|
|
@@ -320,14 +401,7 @@ def connect(
|
|
|
320
401
|
tool = connection["tool"]
|
|
321
402
|
method = connection["method"]
|
|
322
403
|
|
|
323
|
-
#
|
|
324
|
-
if method not in ["credentials", "oauth"]:
|
|
325
|
-
error(f"Connection '{connection_id}' uses '{method}' method")
|
|
326
|
-
info("Only 'credentials' or 'oauth' method connections need OAuth setup")
|
|
327
|
-
info("API connections are already connected after 'afctl tools add'")
|
|
328
|
-
raise typer.Exit(1)
|
|
329
|
-
|
|
330
|
-
# Check if already connected
|
|
404
|
+
# Check if connection is already set up (has credentials stored)
|
|
331
405
|
if connection.get("connected"):
|
|
332
406
|
warning(f"Connection '{connection_id}' is already connected")
|
|
333
407
|
confirm = typer.confirm("Do you want to reconnect (re-authorize)?")
|
|
@@ -413,7 +487,7 @@ def connect(
|
|
|
413
487
|
@app.command()
|
|
414
488
|
def disconnect(
|
|
415
489
|
connection_id: str = typer.Argument(..., help="Connection ID to disconnect"),
|
|
416
|
-
force: bool = typer.Option(False, "--force",
|
|
490
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
417
491
|
):
|
|
418
492
|
"""Disconnect a tool (remove credentials but keep connection entry)."""
|
|
419
493
|
try:
|
|
@@ -466,7 +540,7 @@ def disconnect(
|
|
|
466
540
|
@app.command()
|
|
467
541
|
def remove(
|
|
468
542
|
connection_id: str = typer.Argument(..., help="Connection ID to remove"),
|
|
469
|
-
force: bool = typer.Option(False, "--force",
|
|
543
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
470
544
|
):
|
|
471
545
|
"""Remove a tool connection completely (delete entry and credentials)."""
|
|
472
546
|
try:
|
af_cli/main.py
CHANGED
|
@@ -10,6 +10,7 @@ from rich.console import Console
|
|
|
10
10
|
from rich.table import Table
|
|
11
11
|
|
|
12
12
|
from af_cli.commands.agents import app as agents_app
|
|
13
|
+
from af_cli.commands.applications import app as applications_app
|
|
13
14
|
from af_cli.commands.auth import app as auth_app
|
|
14
15
|
from af_cli.commands.config import app as config_app
|
|
15
16
|
from af_cli.commands.mcp_servers import app as mcp_servers_app
|
|
@@ -31,6 +32,7 @@ app.add_typer(auth_app, name="auth", help="Authentication commands")
|
|
|
31
32
|
app.add_typer(config_app, name="config", help="Configuration commands")
|
|
32
33
|
app.add_typer(agents_app, name="agents", help="Agent management commands")
|
|
33
34
|
app.add_typer(tools_app, name="tools", help="Tool management commands")
|
|
35
|
+
app.add_typer(applications_app, name="applications", help="Application management commands")
|
|
34
36
|
app.add_typer(mcp_servers_app, name="mcp-servers", help="MCP server management commands")
|
|
35
37
|
app.add_typer(secrets_app, name="secrets", help="Secret management commands")
|
|
36
38
|
|
|
@@ -85,19 +87,16 @@ def init(
|
|
|
85
87
|
gateway_url: str = typer.Option(
|
|
86
88
|
"https://dashboard.agenticfabriq.com",
|
|
87
89
|
"--gateway-url",
|
|
88
|
-
"-g",
|
|
89
90
|
help="Gateway URL"
|
|
90
91
|
),
|
|
91
92
|
tenant_id: Optional[str] = typer.Option(
|
|
92
93
|
None,
|
|
93
94
|
"--tenant-id",
|
|
94
|
-
"-t",
|
|
95
95
|
help="Tenant ID"
|
|
96
96
|
),
|
|
97
97
|
force: bool = typer.Option(
|
|
98
98
|
False,
|
|
99
99
|
"--force",
|
|
100
|
-
"-f",
|
|
101
100
|
help="Force initialization, overwrite existing config"
|
|
102
101
|
),
|
|
103
102
|
):
|
|
@@ -134,25 +133,21 @@ def main(
|
|
|
134
133
|
config_file: Optional[str] = typer.Option(
|
|
135
134
|
None,
|
|
136
135
|
"--config",
|
|
137
|
-
"-c",
|
|
138
136
|
help="Path to configuration file"
|
|
139
137
|
),
|
|
140
138
|
gateway_url: Optional[str] = typer.Option(
|
|
141
139
|
None,
|
|
142
140
|
"--gateway-url",
|
|
143
|
-
"-g",
|
|
144
141
|
help="Gateway URL"
|
|
145
142
|
),
|
|
146
143
|
tenant_id: Optional[str] = typer.Option(
|
|
147
144
|
None,
|
|
148
145
|
"--tenant-id",
|
|
149
|
-
"-t",
|
|
150
146
|
help="Tenant ID"
|
|
151
147
|
),
|
|
152
148
|
verbose: bool = typer.Option(
|
|
153
149
|
False,
|
|
154
150
|
"--verbose",
|
|
155
|
-
"-v",
|
|
156
151
|
help="Enable verbose output"
|
|
157
152
|
),
|
|
158
153
|
):
|
af_sdk/__init__.py
CHANGED
|
@@ -23,6 +23,14 @@ from .models.types import (
|
|
|
23
23
|
from .transport.http import HTTPClient
|
|
24
24
|
from .fabriq_client import FabriqClient
|
|
25
25
|
from .models.audit import AuditEvent
|
|
26
|
+
from .auth import (
|
|
27
|
+
get_application_client,
|
|
28
|
+
load_application_config,
|
|
29
|
+
save_application_config,
|
|
30
|
+
list_applications,
|
|
31
|
+
delete_application_config,
|
|
32
|
+
ApplicationNotFoundError,
|
|
33
|
+
)
|
|
26
34
|
|
|
27
35
|
__version__ = "1.0.0"
|
|
28
36
|
|
|
@@ -44,6 +52,13 @@ __all__ = [
|
|
|
44
52
|
"HTTPClient",
|
|
45
53
|
"FabriqClient",
|
|
46
54
|
"AuditEvent",
|
|
55
|
+
# Application auth helpers
|
|
56
|
+
"get_application_client",
|
|
57
|
+
"load_application_config",
|
|
58
|
+
"save_application_config",
|
|
59
|
+
"list_applications",
|
|
60
|
+
"delete_application_config",
|
|
61
|
+
"ApplicationNotFoundError",
|
|
47
62
|
]
|
|
48
63
|
|
|
49
64
|
# Lazy expose dx submodule under af_sdk.dx
|
af_sdk/auth/__init__.py
CHANGED
|
@@ -11,6 +11,15 @@ from .oauth import (
|
|
|
11
11
|
TokenValidator,
|
|
12
12
|
)
|
|
13
13
|
from .token_cache import TokenManager, VaultClient
|
|
14
|
+
from .applications import (
|
|
15
|
+
get_application_client,
|
|
16
|
+
load_application_config,
|
|
17
|
+
save_application_config,
|
|
18
|
+
list_applications,
|
|
19
|
+
delete_application_config,
|
|
20
|
+
ApplicationNotFoundError,
|
|
21
|
+
AuthenticationError,
|
|
22
|
+
)
|
|
14
23
|
|
|
15
24
|
# DPoP helper will be provided from af_sdk.auth.dpop
|
|
16
25
|
try:
|
|
@@ -28,4 +37,11 @@ __all__ = [
|
|
|
28
37
|
"TokenManager",
|
|
29
38
|
"VaultClient",
|
|
30
39
|
"create_dpop_proof",
|
|
40
|
+
"get_application_client",
|
|
41
|
+
"load_application_config",
|
|
42
|
+
"save_application_config",
|
|
43
|
+
"list_applications",
|
|
44
|
+
"delete_application_config",
|
|
45
|
+
"ApplicationNotFoundError",
|
|
46
|
+
"AuthenticationError",
|
|
31
47
|
]
|