apizit-cli 0.2.0b1__tar.gz → 0.2.0b3__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.
Files changed (22) hide show
  1. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/PKG-INFO +14 -4
  2. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/README.md +12 -2
  3. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/pyproject.toml +2 -2
  4. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/__init__.py +1 -1
  5. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/authentication.py +68 -9
  6. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/context.py +1 -2
  7. apizit_cli-0.2.0b3/src/apizit_cli/domains.py +8 -0
  8. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/main.py +9 -1
  9. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli.egg-info/PKG-INFO +14 -4
  10. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli.egg-info/SOURCES.txt +1 -0
  11. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/setup.cfg +0 -0
  12. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/commands.py +0 -0
  13. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/configuration.py +0 -0
  14. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/credential_store.py +0 -0
  15. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/errors.py +0 -0
  16. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/http.py +0 -0
  17. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/operations.py +0 -0
  18. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli/sources.py +0 -0
  19. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli.egg-info/dependency_links.txt +0 -0
  20. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli.egg-info/entry_points.txt +0 -0
  21. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/src/apizit_cli.egg-info/requires.txt +0 -0
  22. {apizit_cli-0.2.0b1 → apizit_cli-0.2.0b3}/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.0b1
4
- Summary: Launch Python APIs with APIZIT from your terminal or CI.
3
+ Version: 0.2.0b3
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 code as a managed public API, inspect logs and manage releases from your terminal.
21
+ Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
22
22
 
23
- APIZIT is an advanced development beta. This client targets its managed dev service.
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 code as a managed public API, inspect logs and manage releases from your terminal.
3
+ Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
4
4
 
5
- APIZIT is an advanced development beta. This client targets its managed dev service.
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.0b1"
8
- description = "Launch Python APIs with APIZIT from your terminal or CI."
7
+ version = "0.2.0b3"
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"}]
@@ -1,3 +1,3 @@
1
1
  """The APIZIT HTTP client. Importing this package never initializes a session."""
2
2
 
3
- __version__ = "0.2.0b1"
3
+ __version__ = "0.2.0b3"
@@ -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,59 @@ class NativeSession:
281
293
  or (len(query.get("error", [])) == 1 and 0 < len(query["error"][0]) <= 256)
282
294
  )
283
295
  )
284
- if valid and len(query.get("code", [])) == 1 and 0 < len(query["code"][0]) <= 4096:
285
- outcome["code"] = query["code"][0]
286
- elif valid and "error" in query:
287
- outcome["error"] = True
288
- self.send_response(200 if valid else 400)
289
- self.send_header("Content-Type", "text/plain; charset=utf-8")
296
+ self._page(
297
+ "Return to the APIZIT terminal." if valid else "Invalid login callback.",
298
+ status=200 if valid else 400,
299
+ )
300
+ # Finish sending the cleanup script before allowing the server to shut down.
301
+ if valid:
302
+ outcome["received_at"] = time.monotonic()
303
+ if "code" in query:
304
+ outcome["code"] = query["code"][0]
305
+ else:
306
+ outcome["error"] = True
307
+
308
+ def _page(self, message, *, status):
309
+ body = (
310
+ '<!doctype html><html lang="en"><head><meta charset="utf-8">'
311
+ "<title>APIZIT sign-in</title>"
312
+ f'<script nonce="{cleanup_nonce}">'
313
+ 'history.replaceState(null,"","/complete");'
314
+ 'fetch("/complete",{method:"POST",credentials:"omit",cache:"no-store",'
315
+ f'headers:{{"X-APIZIT-Page":"{cleanup_nonce}"}}}}).catch(()=>{{}});'
316
+ "</script></head><body><main><h1>APIZIT sign-in</h1>"
317
+ f"<p>{message}</p></main></body></html>"
318
+ ).encode("utf-8")
319
+ self.send_response(status)
320
+ self.send_header("Content-Type", "text/html; charset=utf-8")
321
+ self.send_header("Content-Length", str(len(body)))
290
322
  self.send_header("Cache-Control", "no-store")
291
- self.send_header("Content-Security-Policy", "default-src 'none'")
323
+ self.send_header("Referrer-Policy", "no-referrer")
324
+ self.send_header("X-Content-Type-Options", "nosniff")
325
+ self.send_header(
326
+ "Content-Security-Policy",
327
+ f"default-src 'none'; script-src 'nonce-{cleanup_nonce}'; "
328
+ "connect-src 'self'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
329
+ )
292
330
  self.end_headers()
293
- self.wfile.write(
294
- b"Return to the APIZIT terminal." if valid else b"Invalid login callback."
331
+ self.wfile.write(body)
332
+ self.wfile.flush()
333
+
334
+ def do_POST(self):
335
+ nonlocal page_loaded
336
+ valid = (
337
+ self.path == "/complete"
338
+ and self.headers.get("Host") == callback.netloc
339
+ and hmac.compare_digest(
340
+ self.headers.get("X-APIZIT-Page", "").encode(), cleanup_nonce.encode()
341
+ )
295
342
  )
343
+ if valid and outcome:
344
+ page_loaded = True
345
+ self.send_response(204 if valid else 400)
346
+ self.send_header("Cache-Control", "no-store")
347
+ self.send_header("Content-Length", "0")
348
+ self.end_headers()
296
349
 
297
350
  def log_message(self, *_args):
298
351
  pass
@@ -327,6 +380,12 @@ class NativeSession:
327
380
  server.timeout = 1
328
381
  while not outcome and time.monotonic() < deadline:
329
382
  server.handle_request()
383
+ # The browser acknowledges after replacing its current history entry. A bounded
384
+ # grace period also accommodates clients without JavaScript without blocking login.
385
+ cleanup_deadline = min(deadline, outcome.get("received_at", deadline) + 2)
386
+ while outcome and not page_loaded and time.monotonic() < cleanup_deadline:
387
+ server.timeout = min(0.2, max(0, cleanup_deadline - time.monotonic()))
388
+ server.handle_request()
330
389
  finally:
331
390
  server.server_close()
332
391
  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="Launch Python as a managed public API. APIZIT development beta.",
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.0b1
4
- Summary: Launch Python APIs with APIZIT from your terminal or CI.
3
+ Version: 0.2.0b3
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 code as a managed public API, inspect logs and manage releases from your terminal.
21
+ Launch supported Python, JavaScript, TypeScript or Java projects as managed public APIs, inspect logs and manage releases from your terminal.
22
22
 
23
- APIZIT is an advanced development beta. This client targets its managed dev service.
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
@@ -6,6 +6,7 @@ src/apizit_cli/commands.py
6
6
  src/apizit_cli/configuration.py
7
7
  src/apizit_cli/context.py
8
8
  src/apizit_cli/credential_store.py
9
+ src/apizit_cli/domains.py
9
10
  src/apizit_cli/errors.py
10
11
  src/apizit_cli/http.py
11
12
  src/apizit_cli/main.py
File without changes