apizit-cli 0.2.0b1__tar.gz → 0.2.0b4__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.
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/PKG-INFO +14 -4
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/README.md +12 -2
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/pyproject.toml +2 -2
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/__init__.py +1 -1
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/authentication.py +80 -9
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/context.py +1 -2
- apizit_cli-0.2.0b4/src/apizit_cli/domains.py +8 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/main.py +9 -1
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/PKG-INFO +14 -4
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/SOURCES.txt +1 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/setup.cfg +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/commands.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/configuration.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/credential_store.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/errors.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/http.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/operations.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli/sources.py +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/dependency_links.txt +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/entry_points.txt +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/requires.txt +0 -0
- {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b4}/src/apizit_cli.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apizit-cli
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Launch Python
|
|
3
|
+
Version: 0.2.0b4
|
|
4
|
+
Summary: Launch supported Python, JavaScript, TypeScript or Java APIs from your terminal or CI.
|
|
5
5
|
Author: APIZIT
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
7
7
|
Classifier: Environment :: Console
|
|
@@ -18,9 +18,13 @@ Requires-Dist: pathspec<2,>=1
|
|
|
18
18
|
|
|
19
19
|
# APIZIT CLI
|
|
20
20
|
|
|
21
|
-
Launch Python
|
|
21
|
+
Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Managed adapters cover Flask, FastAPI, Django, Express, NestJS and Spring Boot; APIZIT Linking
|
|
24
|
+
provides declarative Python routes. Run a scan to confirm the project's version and structure.
|
|
25
|
+
|
|
26
|
+
APIZIT is an advanced beta. This source version defaults to `https://api.apizit.com/v1`.
|
|
27
|
+
Version `0.2.0b1` uses its original dev default; use `--endpoint` explicitly with that version.
|
|
24
28
|
Check the official CLI documentation for package availability and current workspace capabilities.
|
|
25
29
|
|
|
26
30
|
Install with `pipx install --pip-args=--pre apizit-cli`
|
|
@@ -30,6 +34,12 @@ The client requires no AWS account, AWS credentials, Docker or APIZIT backend ch
|
|
|
30
34
|
Run `apizit --help` and `apizit docs` for the command reference.
|
|
31
35
|
The package contains the HTTP client and shared configuration contracts only.
|
|
32
36
|
|
|
37
|
+
Use `apizit --endpoint https://api-test.apizit.com/v1 login` to access the test installation.
|
|
38
|
+
Keep that explicit endpoint on subsequent test commands, or set `APIZIT_API_URL` for the terminal
|
|
39
|
+
or CI job. Accounts, saved workspaces and sessions are separate for each endpoint. Sign in again
|
|
40
|
+
when choosing a new address; the CLI never copies an existing session to it. A project already
|
|
41
|
+
linked to another endpoint requires that original explicit endpoint.
|
|
42
|
+
|
|
33
43
|
```sh
|
|
34
44
|
apizit login
|
|
35
45
|
apizit workspace list
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# APIZIT CLI
|
|
2
2
|
|
|
3
|
-
Launch Python
|
|
3
|
+
Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Managed adapters cover Flask, FastAPI, Django, Express, NestJS and Spring Boot; APIZIT Linking
|
|
6
|
+
provides declarative Python routes. Run a scan to confirm the project's version and structure.
|
|
7
|
+
|
|
8
|
+
APIZIT is an advanced beta. This source version defaults to `https://api.apizit.com/v1`.
|
|
9
|
+
Version `0.2.0b1` uses its original dev default; use `--endpoint` explicitly with that version.
|
|
6
10
|
Check the official CLI documentation for package availability and current workspace capabilities.
|
|
7
11
|
|
|
8
12
|
Install with `pipx install --pip-args=--pre apizit-cli`
|
|
@@ -12,6 +16,12 @@ The client requires no AWS account, AWS credentials, Docker or APIZIT backend ch
|
|
|
12
16
|
Run `apizit --help` and `apizit docs` for the command reference.
|
|
13
17
|
The package contains the HTTP client and shared configuration contracts only.
|
|
14
18
|
|
|
19
|
+
Use `apizit --endpoint https://api-test.apizit.com/v1 login` to access the test installation.
|
|
20
|
+
Keep that explicit endpoint on subsequent test commands, or set `APIZIT_API_URL` for the terminal
|
|
21
|
+
or CI job. Accounts, saved workspaces and sessions are separate for each endpoint. Sign in again
|
|
22
|
+
when choosing a new address; the CLI never copies an existing session to it. A project already
|
|
23
|
+
linked to another endpoint requires that original explicit endpoint.
|
|
24
|
+
|
|
15
25
|
```sh
|
|
16
26
|
apizit login
|
|
17
27
|
apizit workspace list
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apizit-cli"
|
|
7
|
-
version = "0.2.
|
|
8
|
-
description = "Launch Python
|
|
7
|
+
version = "0.2.0b4"
|
|
8
|
+
description = "Launch supported Python, JavaScript, TypeScript or Java APIs from your terminal or CI."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
authors = [{name = "APIZIT"}]
|
|
@@ -255,6 +255,8 @@ class NativeSession:
|
|
|
255
255
|
)
|
|
256
256
|
callback = urlsplit(configuration["redirect_uri"])
|
|
257
257
|
outcome = {}
|
|
258
|
+
page_loaded = False
|
|
259
|
+
cleanup_nonce = secrets.token_urlsafe(24)
|
|
258
260
|
deadline = time.monotonic() + timeout
|
|
259
261
|
|
|
260
262
|
class Callback(BaseHTTPRequestHandler):
|
|
@@ -264,12 +266,22 @@ class NativeSession:
|
|
|
264
266
|
|
|
265
267
|
def do_GET(self):
|
|
266
268
|
parsed = urlsplit(self.path)
|
|
269
|
+
if (
|
|
270
|
+
parsed.path == "/complete"
|
|
271
|
+
and not parsed.query
|
|
272
|
+
and not parsed.scheme
|
|
273
|
+
and not parsed.netloc
|
|
274
|
+
and self.headers.get("Host") == callback.netloc
|
|
275
|
+
):
|
|
276
|
+
self._page("Return to the APIZIT terminal.", status=200)
|
|
277
|
+
return
|
|
267
278
|
try:
|
|
268
279
|
query = parse_qs(parsed.query, max_num_fields=8, strict_parsing=True)
|
|
269
280
|
except ValueError:
|
|
270
281
|
query = {}
|
|
271
282
|
valid = (
|
|
272
283
|
parsed.path == callback.path
|
|
284
|
+
and not outcome
|
|
273
285
|
and not parsed.scheme
|
|
274
286
|
and not parsed.netloc
|
|
275
287
|
and self.headers.get("Host") == callback.netloc
|
|
@@ -281,18 +293,71 @@ class NativeSession:
|
|
|
281
293
|
or (len(query.get("error", [])) == 1 and 0 < len(query["error"][0]) <= 256)
|
|
282
294
|
)
|
|
283
295
|
)
|
|
284
|
-
if valid
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
self.
|
|
296
|
+
if not valid:
|
|
297
|
+
self._page("Invalid login callback.", status=400)
|
|
298
|
+
return
|
|
299
|
+
# Redirect before rendering: Chrome's global history retains an initial
|
|
300
|
+
# navigation even when JavaScript replaces its displayed URL afterward.
|
|
301
|
+
self.send_response(303)
|
|
302
|
+
self.send_header("Location", "/complete")
|
|
303
|
+
self.send_header("Content-Length", "0")
|
|
290
304
|
self.send_header("Cache-Control", "no-store")
|
|
291
|
-
self.send_header("
|
|
305
|
+
self.send_header("Referrer-Policy", "no-referrer")
|
|
306
|
+
self.send_header("X-Content-Type-Options", "nosniff")
|
|
307
|
+
self.send_header(
|
|
308
|
+
"Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'"
|
|
309
|
+
)
|
|
292
310
|
self.end_headers()
|
|
293
|
-
self.wfile.
|
|
294
|
-
|
|
311
|
+
self.wfile.flush()
|
|
312
|
+
# Keep serving until the clean landing page acknowledges or the grace ends.
|
|
313
|
+
if valid:
|
|
314
|
+
outcome["received_at"] = time.monotonic()
|
|
315
|
+
if "code" in query:
|
|
316
|
+
outcome["code"] = query["code"][0]
|
|
317
|
+
else:
|
|
318
|
+
outcome["error"] = True
|
|
319
|
+
|
|
320
|
+
def _page(self, message, *, status):
|
|
321
|
+
body = (
|
|
322
|
+
'<!doctype html><html lang="en"><head><meta charset="utf-8">'
|
|
323
|
+
"<title>APIZIT sign-in</title>"
|
|
324
|
+
f'<script nonce="{cleanup_nonce}">'
|
|
325
|
+
'history.replaceState(null,"","/complete");'
|
|
326
|
+
'fetch("/complete",{method:"POST",credentials:"omit",cache:"no-store",'
|
|
327
|
+
f'headers:{{"X-APIZIT-Page":"{cleanup_nonce}"}}}}).catch(()=>{{}});'
|
|
328
|
+
"</script></head><body><main><h1>APIZIT sign-in</h1>"
|
|
329
|
+
f"<p>{message}</p></main></body></html>"
|
|
330
|
+
).encode("utf-8")
|
|
331
|
+
self.send_response(status)
|
|
332
|
+
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
333
|
+
self.send_header("Content-Length", str(len(body)))
|
|
334
|
+
self.send_header("Cache-Control", "no-store")
|
|
335
|
+
self.send_header("Referrer-Policy", "no-referrer")
|
|
336
|
+
self.send_header("X-Content-Type-Options", "nosniff")
|
|
337
|
+
self.send_header(
|
|
338
|
+
"Content-Security-Policy",
|
|
339
|
+
f"default-src 'none'; script-src 'nonce-{cleanup_nonce}'; "
|
|
340
|
+
"connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
|
|
295
341
|
)
|
|
342
|
+
self.end_headers()
|
|
343
|
+
self.wfile.write(body)
|
|
344
|
+
self.wfile.flush()
|
|
345
|
+
|
|
346
|
+
def do_POST(self):
|
|
347
|
+
nonlocal page_loaded
|
|
348
|
+
valid = (
|
|
349
|
+
self.path == "/complete"
|
|
350
|
+
and self.headers.get("Host") == callback.netloc
|
|
351
|
+
and hmac.compare_digest(
|
|
352
|
+
self.headers.get("X-APIZIT-Page", "").encode(), cleanup_nonce.encode()
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
if valid and outcome:
|
|
356
|
+
page_loaded = True
|
|
357
|
+
self.send_response(204 if valid else 400)
|
|
358
|
+
self.send_header("Cache-Control", "no-store")
|
|
359
|
+
self.send_header("Content-Length", "0")
|
|
360
|
+
self.end_headers()
|
|
296
361
|
|
|
297
362
|
def log_message(self, *_args):
|
|
298
363
|
pass
|
|
@@ -327,6 +392,12 @@ class NativeSession:
|
|
|
327
392
|
server.timeout = 1
|
|
328
393
|
while not outcome and time.monotonic() < deadline:
|
|
329
394
|
server.handle_request()
|
|
395
|
+
# The browser acknowledges after replacing its current history entry. A bounded
|
|
396
|
+
# grace period also accommodates clients without JavaScript without blocking login.
|
|
397
|
+
cleanup_deadline = min(deadline, outcome.get("received_at", deadline) + 2)
|
|
398
|
+
while outcome and not page_loaded and time.monotonic() < cleanup_deadline:
|
|
399
|
+
server.timeout = min(0.2, max(0, cleanup_deadline - time.monotonic()))
|
|
400
|
+
server.handle_request()
|
|
330
401
|
finally:
|
|
331
402
|
server.server_close()
|
|
332
403
|
if "code" not in outcome:
|
|
@@ -9,8 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
from urllib.parse import urlsplit
|
|
10
10
|
|
|
11
11
|
from apizit_cli.errors import CliError, EXIT_USAGE
|
|
12
|
-
|
|
13
|
-
DEFAULT_API_ORIGIN = "https://jxo6vbfwy0.execute-api.eu-central-1.amazonaws.com/v1"
|
|
12
|
+
from apizit_cli.domains import DEFAULT_API_ORIGIN
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
def normalize_origin(value: str) -> str:
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Generated by infra/scripts/export_platform_domains.py --cli; do not edit."""
|
|
2
|
+
|
|
3
|
+
DEFAULT_ENVIRONMENT = "beta"
|
|
4
|
+
API_ORIGINS = {
|
|
5
|
+
"dev": "https://api-test.apizit.com/v1",
|
|
6
|
+
"beta": "https://api.apizit.com/v1",
|
|
7
|
+
}
|
|
8
|
+
DEFAULT_API_ORIGIN = API_ORIGINS[DEFAULT_ENVIRONMENT]
|
|
@@ -51,7 +51,15 @@ def build_parser():
|
|
|
51
51
|
add_options(common, GLOBAL_OPTIONS, global_options=True)
|
|
52
52
|
parser = Parser(
|
|
53
53
|
prog="apizit",
|
|
54
|
-
description=
|
|
54
|
+
description=(
|
|
55
|
+
"Launch supported Python, JavaScript, TypeScript or Java projects as managed public "
|
|
56
|
+
"APIs. Framework support follows the APIZIT compatibility guide. APIZIT prelaunch beta."
|
|
57
|
+
),
|
|
58
|
+
epilog=(
|
|
59
|
+
"Managed frameworks: Flask, FastAPI, Django, Express, NestJS and Spring Boot. "
|
|
60
|
+
"APIZIT Linking supports declarative Python routes. Run a scan to confirm that your "
|
|
61
|
+
"project's version and structure are compatible."
|
|
62
|
+
),
|
|
55
63
|
parents=[common],
|
|
56
64
|
allow_abbrev=False,
|
|
57
65
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apizit-cli
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Launch Python
|
|
3
|
+
Version: 0.2.0b4
|
|
4
|
+
Summary: Launch supported Python, JavaScript, TypeScript or Java APIs from your terminal or CI.
|
|
5
5
|
Author: APIZIT
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
7
7
|
Classifier: Environment :: Console
|
|
@@ -18,9 +18,13 @@ Requires-Dist: pathspec<2,>=1
|
|
|
18
18
|
|
|
19
19
|
# APIZIT CLI
|
|
20
20
|
|
|
21
|
-
Launch Python
|
|
21
|
+
Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Managed adapters cover Flask, FastAPI, Django, Express, NestJS and Spring Boot; APIZIT Linking
|
|
24
|
+
provides declarative Python routes. Run a scan to confirm the project's version and structure.
|
|
25
|
+
|
|
26
|
+
APIZIT is an advanced beta. This source version defaults to `https://api.apizit.com/v1`.
|
|
27
|
+
Version `0.2.0b1` uses its original dev default; use `--endpoint` explicitly with that version.
|
|
24
28
|
Check the official CLI documentation for package availability and current workspace capabilities.
|
|
25
29
|
|
|
26
30
|
Install with `pipx install --pip-args=--pre apizit-cli`
|
|
@@ -30,6 +34,12 @@ The client requires no AWS account, AWS credentials, Docker or APIZIT backend ch
|
|
|
30
34
|
Run `apizit --help` and `apizit docs` for the command reference.
|
|
31
35
|
The package contains the HTTP client and shared configuration contracts only.
|
|
32
36
|
|
|
37
|
+
Use `apizit --endpoint https://api-test.apizit.com/v1 login` to access the test installation.
|
|
38
|
+
Keep that explicit endpoint on subsequent test commands, or set `APIZIT_API_URL` for the terminal
|
|
39
|
+
or CI job. Accounts, saved workspaces and sessions are separate for each endpoint. Sign in again
|
|
40
|
+
when choosing a new address; the CLI never copies an existing session to it. A project already
|
|
41
|
+
linked to another endpoint requires that original explicit endpoint.
|
|
42
|
+
|
|
33
43
|
```sh
|
|
34
44
|
apizit login
|
|
35
45
|
apizit workspace list
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|