pz-cli 5.0.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.
- pz_cli-5.0.0.dist-info/METADATA +51 -0
- pz_cli-5.0.0.dist-info/RECORD +399 -0
- pz_cli-5.0.0.dist-info/WHEEL +4 -0
- pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
- pz_core/__init__.py +64 -0
- pz_core/__main__.py +7 -0
- pz_core/app.py +45 -0
- pz_core/assembly/__init__.py +17 -0
- pz_core/assembly/app_discovery.py +1240 -0
- pz_core/assembly/apps/__init__.py +25 -0
- pz_core/assembly/apps/compiler.py +824 -0
- pz_core/assembly/apps/providers.py +188 -0
- pz_core/assembly/cli/__init__.py +9 -0
- pz_core/assembly/cli/compiler.py +166 -0
- pz_core/assembly/diagnostics/__init__.py +21 -0
- pz_core/assembly/diagnostics/checks.py +257 -0
- pz_core/assembly/diagnostics/dev_sources.py +569 -0
- pz_core/assembly/events/__init__.py +5 -0
- pz_core/assembly/events/compiler.py +219 -0
- pz_core/assembly/extensions/__init__.py +5 -0
- pz_core/assembly/extensions/compiler.py +696 -0
- pz_core/assembly/infra/__init__.py +6 -0
- pz_core/assembly/infra/compiler.py +272 -0
- pz_core/assembly/lifecycle/__init__.py +5 -0
- pz_core/assembly/lifecycle/compiler.py +95 -0
- pz_core/assembly/middlewares/__init__.py +19 -0
- pz_core/assembly/middlewares/compiler.py +508 -0
- pz_core/assembly/project/__init__.py +7 -0
- pz_core/assembly/project/compiler.py +9 -0
- pz_core/assembly/project/context.py +17 -0
- pz_core/assembly/project/discovery.py +227 -0
- pz_core/assembly/resources/__init__.py +19 -0
- pz_core/assembly/resources/compiler.py +310 -0
- pz_core/assembly/resources/settings.py +129 -0
- pz_core/assembly/routes/__init__.py +7 -0
- pz_core/assembly/routes/compiler.py +400 -0
- pz_core/assembly/runtime_manifests/__init__.py +13 -0
- pz_core/assembly/runtime_manifests/compiler.py +159 -0
- pz_core/assembly/settings/__init__.py +17 -0
- pz_core/assembly/settings/compiler.py +786 -0
- pz_core/assembly/settings/host_project_overrides.py +82 -0
- pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
- pz_core/authoring/__init__.py +79 -0
- pz_core/authoring/app_init_service.py +946 -0
- pz_core/authoring/app_versions.py +814 -0
- pz_core/authoring/cli.py +192 -0
- pz_core/authoring/commands.py +1810 -0
- pz_core/authoring/conflicts.py +180 -0
- pz_core/authoring/dev_bindings.py +916 -0
- pz_core/authoring/dev_git.py +1087 -0
- pz_core/authoring/dev_import.py +1061 -0
- pz_core/authoring/dev_manifest.py +522 -0
- pz_core/authoring/dev_sources.py +1638 -0
- pz_core/authoring/env_cli.py +454 -0
- pz_core/authoring/files.py +109 -0
- pz_core/authoring/ide_projection.py +1129 -0
- pz_core/authoring/naming.py +58 -0
- pz_core/authoring/official_dev_sources.py +432 -0
- pz_core/authoring/official_sources.json +156 -0
- pz_core/authoring/orchestration_service.py +558 -0
- pz_core/authoring/project_default.jsonc +53 -0
- pz_core/authoring/project_defaults.py +88 -0
- pz_core/authoring/project_metadata_service.py +199 -0
- pz_core/authoring/project_settings_checks.py +51 -0
- pz_core/authoring/project_settings_cli.py +299 -0
- pz_core/authoring/project_settings_service.py +1700 -0
- pz_core/authoring/project_state.py +399 -0
- pz_core/authoring/publish_git.py +423 -0
- pz_core/authoring/publish_lock.py +188 -0
- pz_core/authoring/publish_source.py +195 -0
- pz_core/authoring/release.py +1382 -0
- pz_core/authoring/repo_keys.py +29 -0
- pz_core/authoring/root_cli.py +28 -0
- pz_core/authoring/scaffold_service.py +325 -0
- pz_core/authoring/sync_service.py +787 -0
- pz_core/authoring/templates/app/__init__.py +1 -0
- pz_core/authoring/templates/app/api.py +25 -0
- pz_core/authoring/templates/app/apps.py +31 -0
- pz_core/authoring/templates/app/auth_package_init.py +14 -0
- pz_core/authoring/templates/app/auth_readme.py +29 -0
- pz_core/authoring/templates/app/configs_package_init.py +14 -0
- pz_core/authoring/templates/app/default_env.py +18 -0
- pz_core/authoring/templates/app/default_jsonc.py +25 -0
- pz_core/authoring/templates/app/locales_readme.py +25 -0
- pz_core/authoring/templates/app/migrations_readme.py +19 -0
- pz_core/authoring/templates/app/models.py +14 -0
- pz_core/authoring/templates/app/package_init.py +8 -0
- pz_core/authoring/templates/app/pages_base.py +161 -0
- pz_core/authoring/templates/app/pages_readme.py +25 -0
- pz_core/authoring/templates/app/public.py +31 -0
- pz_core/authoring/templates/app/pyproject.py +77 -0
- pz_core/authoring/templates/app/readme.py +74 -0
- pz_core/authoring/templates/app/settings.py +46 -0
- pz_core/authoring/templates/app/static_app_js.py +24 -0
- pz_core/authoring/templates/app/static_readme.py +31 -0
- pz_core/authoring/templates/app/template_config_page.py +23 -0
- pz_core/authoring/templates/app/template_index_html.py +28 -0
- pz_core/authoring/templates/app/templates_readme.py +32 -0
- pz_core/authoring/templates/app/urls.py +36 -0
- pz_core/authoring/templates/app/views.py +36 -0
- pz_core/authoring/templates/project/__init__.py +1 -0
- pz_core/authoring/templates/project/agents.py +51 -0
- pz_core/authoring/templates/project/apps_container_readme.py +37 -0
- pz_core/authoring/templates/project/main_py.py +59 -0
- pz_core/authoring/templates/project/project_env.py +19 -0
- pz_core/authoring/templates/project/pyproject.py +26 -0
- pz_core/authoring/templates/project/pz_env_env.py +65 -0
- pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
- pz_core/authoring/templates/project/pz_jsonc.py +12 -0
- pz_core/authoring/templates/project/readme.py +94 -0
- pz_core/authoring/templates/project/root_gitkeep.py +8 -0
- pz_core/authoring/templates/shared/__init__.py +5 -0
- pz_core/authoring/templates/shared/text.py +10 -0
- pz_core/authoring/venv_service.py +87 -0
- pz_core/authoring/workspace.py +167 -0
- pz_core/cli.py +291 -0
- pz_core/cli_options.py +74 -0
- pz_core/core/__init__.py +3 -0
- pz_core/core/errors/__init__.py +5 -0
- pz_core/core/errors/models.py +117 -0
- pz_core/core/events/__init__.py +5 -0
- pz_core/core/events/registry.py +54 -0
- pz_core/core/extensions/__init__.py +51 -0
- pz_core/core/extensions/registry.py +790 -0
- pz_core/core/health/__init__.py +6 -0
- pz_core/core/health/contracts.py +10 -0
- pz_core/core/middlewares/__init__.py +6 -0
- pz_core/core/middlewares/models.py +24 -0
- pz_core/core/routing/__init__.py +5 -0
- pz_core/core/routing/models.py +21 -0
- pz_core/core/settings_contracts.py +25 -0
- pz_core/docs/README.md +20 -0
- pz_core/docs/distribution-README.md +438 -0
- pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/00-pz/346/236/266/346/236/204/346/200/273/347/272/262.md +240 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/350/247/204/350/214/203.md +216 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203.md +403 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/03-App/346/234/200/345/260/217/345/255/220/345/214/205/350/247/204/350/214/203.md +571 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/04-Settings/344/270/216/351/205/215/347/275/256/350/247/204/350/214/203.md +1177 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/05-/350/265/204/346/272/220/344/270/216/350/277/220/350/241/214/347/233/256/345/275/225/350/247/204/350/214/203.md +575 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/06-/346/225/260/346/215/256/345/272/223/344/270/216/345/217/257/351/200/211/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/350/214/203.md +499 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/07-App/346/233/277/346/215/242/350/247/204/350/214/203.md +206 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/08-/345/271/263/345/217/260/347/272/247App/344/270/216/350/277/220/350/241/214/346/227/266/345/215/225/344/276/213/350/247/204/350/214/203.md +445 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/09-CLI/344/270/216Worker/345/205/245/345/217/243/350/247/204/350/214/203.md +950 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/10-/346/265/213/350/257/225/344/270/216/345/245/221/347/272/246/350/247/204/350/214/203.md +1001 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/11-/344/273/223/345/272/223/347/234/237/347/233/270/346/272/220/345/234/260/345/233/276.md +102 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/12-/346/236/204/345/273/272/344/270/216/345/217/221/345/270/203/346/243/200/346/237/245/346/270/205/345/215/225.md +171 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/13-/346/255/243/345/274/217Facade/346/200/273/350/241/250.md +402 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/14-/345/210/206/345/261/202/344/270/216/346/211/251/345/261/225/350/247/204/350/214/203.md +550 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/15-/345/255/220/345/214/205/345/274/200/345/217/221/344/275/277/347/224/250/346/211/213/345/206/214.md +1004 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/16-/346/211/251/345/261/225/347/202/271/346/255/243/345/274/217/345/215/217/350/256/256/346/270/205/345/215/225.md +352 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/17-pz.protocols.v1/346/255/243/345/274/217/345/215/217/350/256/256.md +266 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/18-/346/211/251/345/261/225/347/202/271/345/206/262/347/252/201/350/243/201/345/206/263/346/200/273/350/241/250.md +131 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/19-/351/224/231/350/257/257/347/240/201/344/270/216/350/257/212/346/226/255/345/215/217/350/256/256.md +176 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/20-/347/247/201/346/234/211/345/214/205/344/273/223/344/270/216/347/273/237/344/270/200/350/256/244/350/257/201/351/203/250/347/275/262/350/247/204/350/214/203.md +243 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/21-contrib/347/272/246/345/256/232/344/270/216Provider/346/216/245/345/205/245/350/247/204/350/214/203.md +365 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/22-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203.md +912 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/23-/351/246/226/345/261/217/345/261/225/347/244/272/344/270/216/351/246/226/345/270/247/347/250/263/345/256/232/350/247/204/350/214/203.md +269 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/24-pz/345/220/257/345/212/250/344/270/216/350/277/220/350/241/214/346/227/266/347/274/226/350/257/221/346/265/201/347/250/213.md +245 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/25-/351/235/242/345/220/221/345/257/271/350/261/241/345/274/200/345/217/221/350/247/204/350/214/203.md +300 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/00-legacy_core/346/240/207/345/207/206pip/345/214/205/345/214/226/351/207/215/346/236/204/346/200/273/347/272/262.md +1073 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +224 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203-/345/220/253/345/216/206/345/217/262/345/217/243/345/276/204.md +671 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/13-/344/270/200/346/254/241/346/200/247/345/256/236/346/226/275/346/270/205/345/215/225.md +387 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/14-/345/255/220/345/214/205/351/200/202/351/205/215/346/224/271/351/200/240/346/270/205/345/215/225.md +592 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/15-infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/346/270/205/345/215/225.md +81 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/19-core/345/215/225/344/270/200/346/255/243/345/274/217/346/226/271/346/241/210/346/224/266/346/225/233/346/211/247/350/241/214/346/270/205/345/215/225.md +161 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/25-/345/215/217/350/256/256/345/210/260/346/272/220/347/240/201/345/267/256/350/267/235/346/270/205/345/215/225.md +377 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/26-cutover/345/256/214/345/267/245/346/243/200/346/237/245/346/270/205/345/215/225.md +117 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/29-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203-/345/220/253/350/277/201/347/247/273/347/255/226/347/225/245.md +956 -0
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/99-/350/265/204/346/272/220/346/224/266/345/217/243/345/220/216/347/273/255TODO.md +84 -0
- pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
- pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
- pz_core/infra/__init__.py +17 -0
- pz_core/infra/db/__init__.py +23 -0
- pz_core/infra/db/contracts.py +73 -0
- pz_core/infra/health/__init__.py +5 -0
- pz_core/infra/health/contracts.py +8 -0
- pz_core/infra/kv/__init__.py +5 -0
- pz_core/infra/kv/contracts.py +17 -0
- pz_core/infra/observability/__init__.py +23 -0
- pz_core/infra/observability/contracts.py +142 -0
- pz_core/infra/resilience/__init__.py +5 -0
- pz_core/infra/resilience/contracts.py +17 -0
- pz_core/infra/resources/__init__.py +5 -0
- pz_core/infra/resources/contracts.py +16 -0
- pz_core/infra/settings/__init__.py +17 -0
- pz_core/infra/settings/models.py +81 -0
- pz_core/infra/storage/__init__.py +5 -0
- pz_core/infra/storage/ports.py +27 -0
- pz_core/project_root_commands.py +282 -0
- pz_core/project_runtime_cli.py +344 -0
- pz_core/project_sources.py +253 -0
- pz_core/pz_launcher.py +209 -0
- pz_core/root_cli.py +70 -0
- pz_core/runtime/__init__.py +229 -0
- pz_core/runtime/access.py +86 -0
- pz_core/runtime/adapters/__init__.py +5 -0
- pz_core/runtime/adapters/base.py +18 -0
- pz_core/runtime/asyncio_bridge.py +18 -0
- pz_core/runtime/bindings/__init__.py +5 -0
- pz_core/runtime/bindings/container.py +50 -0
- pz_core/runtime/cli/__init__.py +5 -0
- pz_core/runtime/cli/_args.py +67 -0
- pz_core/runtime/cli/app_commands.py +417 -0
- pz_core/runtime/cli/check.py +214 -0
- pz_core/runtime/cli/db.py +297 -0
- pz_core/runtime/cli/main.py +89 -0
- pz_core/runtime/cli/resources.py +280 -0
- pz_core/runtime/discovery.py +23 -0
- pz_core/runtime/environment_integrity.py +157 -0
- pz_core/runtime/errors.py +5 -0
- pz_core/runtime/events.py +87 -0
- pz_core/runtime/facades/__init__.py +38 -0
- pz_core/runtime/facades/_capabilities.py +46 -0
- pz_core/runtime/facades/cache.py +103 -0
- pz_core/runtime/facades/database.py +71 -0
- pz_core/runtime/facades/events.py +380 -0
- pz_core/runtime/facades/health.py +101 -0
- pz_core/runtime/facades/mail.py +121 -0
- pz_core/runtime/facades/observability.py +102 -0
- pz_core/runtime/facades/providers.py +75 -0
- pz_core/runtime/facades/resources.py +52 -0
- pz_core/runtime/facades/storage.py +296 -0
- pz_core/runtime/health/__init__.py +5 -0
- pz_core/runtime/health/service.py +102 -0
- pz_core/runtime/host.py +188 -0
- pz_core/runtime/host_runner.py +282 -0
- pz_core/runtime/http/__init__.py +20 -0
- pz_core/runtime/http/app.py +576 -0
- pz_core/runtime/http_timing.py +173 -0
- pz_core/runtime/invocation.py +29 -0
- pz_core/runtime/json_safe.py +47 -0
- pz_core/runtime/lifecycle/__init__.py +25 -0
- pz_core/runtime/lifecycle/manager.py +533 -0
- pz_core/runtime/plan.py +214 -0
- pz_core/runtime/plan_context.py +33 -0
- pz_core/runtime/plan_snapshot.py +177 -0
- pz_core/runtime/registries/__init__.py +27 -0
- pz_core/runtime/registries/capabilities.py +101 -0
- pz_core/runtime/registries/providers.py +396 -0
- pz_core/runtime/resource_assets.py +344 -0
- pz_core/runtime/run_cli.py +211 -0
- pz_core/runtime/settings.py +888 -0
- pz_core/runtime/worker/__init__.py +21 -0
- pz_core/runtime/worker/engine.py +921 -0
- pz_core/runtime/worker/runtime.py +25 -0
- pz_core/testing/__init__.py +15 -0
- pz_core/testing/doc_route_contracts.py +305 -0
- pz_core/utils/__init__.py +44 -0
- pz_core/utils/env.py +65 -0
- pz_core/utils/project_jsonc/__init__.py +29 -0
- pz_core/utils/project_jsonc/document.py +420 -0
- pz_core/utils/project_settings.py +99 -0
- pz_foundation/__init__.py +50 -0
- pz_foundation/_contracts.py +81 -0
- pz_foundation/_errors.py +34 -0
- pz_foundation/api.py +14 -0
- pz_foundation/apps.py +127 -0
- pz_foundation/auth/__init__.py +1 -0
- pz_foundation/cache_control.py +233 -0
- pz_foundation/cli/__init__.py +2 -0
- pz_foundation/cli/workers.py +565 -0
- pz_foundation/configs/__init__.py +0 -0
- pz_foundation/configs/default.env +15 -0
- pz_foundation/configs/default.jsonc +452 -0
- pz_foundation/db/__init__.py +94 -0
- pz_foundation/db/aerich_executor.py +664 -0
- pz_foundation/db/config.py +358 -0
- pz_foundation/db/connection_manager.py +689 -0
- pz_foundation/db/connection_probe.py +204 -0
- pz_foundation/db/database.py +1291 -0
- pz_foundation/db/deps.py +47 -0
- pz_foundation/db/lifecycle_status.py +85 -0
- pz_foundation/db/migrations.py +477 -0
- pz_foundation/db/mysql.py +57 -0
- pz_foundation/db/postgresql.py +409 -0
- pz_foundation/db/production_pool_fallback.py +143 -0
- pz_foundation/db/public.py +45 -0
- pz_foundation/db/session.py +369 -0
- pz_foundation/db/sqlite.py +15 -0
- pz_foundation/db/tortoise_manager.py +724 -0
- pz_foundation/db/tortoise_psycopg.py +148 -0
- pz_foundation/docs/README.md +18 -0
- pz_foundation/docs/distribution-README.md +319 -0
- pz_foundation/docs/infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/350/257/264/346/230/216.md +39 -0
- pz_foundation/docs//345/205/254/345/274/200/345/205/215/350/264/271/346/216/245/345/217/243/351/230/262/346/273/245/347/224/250/344/270/216/344/272/272/346/234/272/346/240/241/351/252/214.md +680 -0
- pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
- pz_foundation/docs//350/267/257/347/224/261/344/270/216URL/345/244/204/347/220/206/350/247/204/350/214/203.md +119 -0
- pz_foundation/health.py +105 -0
- pz_foundation/host/__init__.py +11 -0
- pz_foundation/host/builder.py +34 -0
- pz_foundation/host/cache_runtime.py +44 -0
- pz_foundation/host/db/__init__.py +17 -0
- pz_foundation/host/db/aerich_config.py +36 -0
- pz_foundation/host/db/config.py +106 -0
- pz_foundation/host/db/connection_manager.py +48 -0
- pz_foundation/host/db/deps.py +5 -0
- pz_foundation/host/db/orm_retry_patch.py +566 -0
- pz_foundation/host/db/request_adapter.py +325 -0
- pz_foundation/host/db/router.py +28 -0
- pz_foundation/host/db/session.py +284 -0
- pz_foundation/host/db/tortoise_manager.py +10 -0
- pz_foundation/host/idempotency.py +132 -0
- pz_foundation/host/lifespan.py +247 -0
- pz_foundation/host/redis_runtime.py +100 -0
- pz_foundation/host/web.py +790 -0
- pz_foundation/infra_provider.py +236 -0
- pz_foundation/kv/__init__.py +25 -0
- pz_foundation/kv/cache.py +1166 -0
- pz_foundation/kv/deps.py +84 -0
- pz_foundation/kv/public.py +25 -0
- pz_foundation/kv/redis_manager.py +1531 -0
- pz_foundation/lazy_exports.py +43 -0
- pz_foundation/lazy_imports.py +124 -0
- pz_foundation/lifecycle.py +392 -0
- pz_foundation/managed_workers.py +1117 -0
- pz_foundation/middlewares/__init__.py +26 -0
- pz_foundation/middlewares/_settings.py +250 -0
- pz_foundation/middlewares/analytics.py +124 -0
- pz_foundation/middlewares/cache_control.py +156 -0
- pz_foundation/middlewares/compression.py +202 -0
- pz_foundation/middlewares/cors.py +62 -0
- pz_foundation/middlewares/geo_country.py +44 -0
- pz_foundation/middlewares/inner_router.py +50 -0
- pz_foundation/middlewares/rate_limited/__init__.py +3 -0
- pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
- pz_foundation/middlewares/request_logging.py +104 -0
- pz_foundation/middlewares/route_owner.py +309 -0
- pz_foundation/middlewares/security_csrf.py +44 -0
- pz_foundation/middlewares/security_headers/__init__.py +4 -0
- pz_foundation/middlewares/security_headers/conflicts.py +44 -0
- pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
- pz_foundation/middlewares/security_headers/security_headers.py +44 -0
- pz_foundation/migrations/__init__.py +1 -0
- pz_foundation/migrations/pz_foundation/__init__.py +1 -0
- pz_foundation/models.py +22 -0
- pz_foundation/notifications/__init__.py +23 -0
- pz_foundation/notifications/email.py +542 -0
- pz_foundation/notifications/public.py +31 -0
- pz_foundation/observability/__init__.py +71 -0
- pz_foundation/observability/http.py +34 -0
- pz_foundation/observability/logger/__init__.py +49 -0
- pz_foundation/observability/logger/_bot_settings.py +126 -0
- pz_foundation/observability/logger/bot_message.py +592 -0
- pz_foundation/observability/logger/core.py +385 -0
- pz_foundation/observability/logger/delivery_audit.py +84 -0
- pz_foundation/observability/logger/feishu_bot.py +199 -0
- pz_foundation/observability/logger/telegram_bot.py +194 -0
- pz_foundation/observability/metrics.py +365 -0
- pz_foundation/observability/runtime.py +68 -0
- pz_foundation/public.py +405 -0
- pz_foundation/resources/__init__.py +12 -0
- pz_foundation/resources/builder.py +900 -0
- pz_foundation/resources/images.py +363 -0
- pz_foundation/root_cli.py +20 -0
- pz_foundation/routing/__init__.py +203 -0
- pz_foundation/routing/canonical.py +486 -0
- pz_foundation/routing/convertors.py +82 -0
- pz_foundation/routing/declarations.py +843 -0
- pz_foundation/routing/exports.py +148 -0
- pz_foundation/routing/loaders.py +138 -0
- pz_foundation/routing/manifest.py +215 -0
- pz_foundation/routing/manifest_provider.py +47 -0
- pz_foundation/routing/mounts.py +101 -0
- pz_foundation/routing/ordering.py +172 -0
- pz_foundation/routing/registry.py +133 -0
- pz_foundation/routing/utils.py +28 -0
- pz_foundation/runtime.py +234 -0
- pz_foundation/settings.py +253 -0
- pz_foundation/settings_normalization.py +130 -0
- pz_foundation/storage/__init__.py +25 -0
- pz_foundation/storage/local.py +209 -0
- pz_foundation/storage/public.py +106 -0
- pz_foundation/storage/s3.py +116 -0
- pz_foundation/storage/service.py +234 -0
- pz_foundation/urls.py +19 -0
- pz_foundation/utils/__init__.py +6 -0
- pz_foundation/utils/merge.py +160 -0
- pz_foundation/worker_replicas.py +55 -0
- pz_settings_center/__init__.py +5 -0
- pz_settings_center/api/__init__.py +5 -0
- pz_settings_center/api/runtime_overrides.py +360 -0
- pz_settings_center/apps.py +28 -0
- pz_settings_center/configs/__init__.py +0 -0
- pz_settings_center/configs/default.env +2 -0
- pz_settings_center/configs/default.jsonc +1 -0
- pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
- pz_settings_center/docs/README.md +12 -0
- pz_settings_center/docs/distribution-README.md +150 -0
- pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
- pz_settings_center/integration_payload.py +18 -0
- pz_settings_center/project_helpers.py +405 -0
- pz_settings_center/public.py +139 -0
- pz_settings_center/routing_helpers.py +73 -0
- pz_settings_center/runtime_override_provider.py +61 -0
- pz_settings_center/typed_settings.py +324 -0
- pz_settings_center/urls.py +9 -0
|
@@ -0,0 +1,790 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from importlib import import_module
|
|
5
|
+
import inspect
|
|
6
|
+
from typing import Any, TypeAlias
|
|
7
|
+
|
|
8
|
+
from pz_core.core.errors import PzError
|
|
9
|
+
|
|
10
|
+
WORKER_ROLE_KINDS = frozenset(
|
|
11
|
+
{
|
|
12
|
+
"infrastructure_worker",
|
|
13
|
+
"operator_ingress_worker",
|
|
14
|
+
"resident_actor_worker",
|
|
15
|
+
"task_driven_actor_worker",
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _resolve_dotted(target: str) -> Any:
|
|
21
|
+
module_name, attr_name = str(target or "").rsplit(".", 1)
|
|
22
|
+
module = import_module(module_name)
|
|
23
|
+
return getattr(module, attr_name)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _instantiate_extension_target(target: Any) -> Any:
|
|
27
|
+
if isinstance(target, str):
|
|
28
|
+
target = _resolve_dotted(target)
|
|
29
|
+
if inspect.isclass(target):
|
|
30
|
+
return target()
|
|
31
|
+
return target
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class ExtensionSpec:
|
|
36
|
+
id: str
|
|
37
|
+
kind: str
|
|
38
|
+
owner_app: str
|
|
39
|
+
api_version: str = "v1"
|
|
40
|
+
priority: int = 100
|
|
41
|
+
title: str = ""
|
|
42
|
+
payload: dict[str, Any] = field(default_factory=dict)
|
|
43
|
+
source: str = ""
|
|
44
|
+
provides: tuple[str, ...] = ()
|
|
45
|
+
conflicts: tuple[str, ...] = ()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _is_declarative_payload_value(value: Any) -> bool:
|
|
49
|
+
if value is None or isinstance(value, (str, int, float, bool)):
|
|
50
|
+
return True
|
|
51
|
+
if isinstance(value, (list, tuple)):
|
|
52
|
+
return all(_is_declarative_payload_value(item) for item in value)
|
|
53
|
+
if isinstance(value, dict):
|
|
54
|
+
return all(
|
|
55
|
+
isinstance(key, str) and _is_declarative_payload_value(item)
|
|
56
|
+
for key, item in value.items()
|
|
57
|
+
)
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(frozen=True, slots=True)
|
|
62
|
+
class HostBuildContext:
|
|
63
|
+
project: Any
|
|
64
|
+
plan: Any
|
|
65
|
+
settings: Any
|
|
66
|
+
bindings: Any
|
|
67
|
+
lifecycle_state: Any | None = None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True, slots=True)
|
|
71
|
+
class HostBuildResult:
|
|
72
|
+
app: Any
|
|
73
|
+
app_kind: str = "asgi"
|
|
74
|
+
health_path: str | None = None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(frozen=True, slots=True)
|
|
78
|
+
class HostBuilderSpec:
|
|
79
|
+
id: str
|
|
80
|
+
owner_app: str
|
|
81
|
+
builder: Any
|
|
82
|
+
kind: str = "host.builder"
|
|
83
|
+
runtime_kind: str = "web"
|
|
84
|
+
api_version: str = "v1"
|
|
85
|
+
priority: int = 100
|
|
86
|
+
title: str = ""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass(frozen=True, slots=True)
|
|
90
|
+
class SettingsPatch:
|
|
91
|
+
app_id: str
|
|
92
|
+
payload: dict[str, Any]
|
|
93
|
+
source: str
|
|
94
|
+
priority: int = 100
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(frozen=True, slots=True)
|
|
98
|
+
class SettingsProviderContext:
|
|
99
|
+
project: Any
|
|
100
|
+
snapshot: Any
|
|
101
|
+
settings: Any
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass(frozen=True, slots=True)
|
|
105
|
+
class SettingsProviderSpec:
|
|
106
|
+
id: str
|
|
107
|
+
owner_app: str
|
|
108
|
+
provider: Any
|
|
109
|
+
kind: str = "settings.provider"
|
|
110
|
+
api_version: str = "v1"
|
|
111
|
+
priority: int = 100
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass(frozen=True, slots=True)
|
|
115
|
+
class InfraPatch:
|
|
116
|
+
component: str
|
|
117
|
+
payload: dict[str, Any]
|
|
118
|
+
source: str
|
|
119
|
+
priority: int = 100
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True, slots=True)
|
|
123
|
+
class InfraProviderContext:
|
|
124
|
+
project: Any
|
|
125
|
+
snapshot: Any
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@dataclass(frozen=True, slots=True)
|
|
129
|
+
class InfraProviderSpec:
|
|
130
|
+
id: str
|
|
131
|
+
owner_app: str
|
|
132
|
+
provider: Any
|
|
133
|
+
kind: str = "infra.provider"
|
|
134
|
+
api_version: str = "v1"
|
|
135
|
+
priority: int = 100
|
|
136
|
+
title: str = ""
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass(frozen=True, slots=True)
|
|
140
|
+
class RuntimeManifestContributionSpec:
|
|
141
|
+
id: str
|
|
142
|
+
owner_app: str
|
|
143
|
+
provider: Any
|
|
144
|
+
kind: str = "runtime.manifest_contribution"
|
|
145
|
+
api_version: str = "v1"
|
|
146
|
+
priority: int = 100
|
|
147
|
+
title: str = ""
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass(frozen=True, slots=True)
|
|
151
|
+
class LifecycleContributionSpec:
|
|
152
|
+
id: str
|
|
153
|
+
owner_app: str
|
|
154
|
+
handler: Any
|
|
155
|
+
phase: str
|
|
156
|
+
kind: str = "lifecycle.contribution"
|
|
157
|
+
api_version: str = "v1"
|
|
158
|
+
priority: int = 100
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@dataclass(frozen=True, slots=True)
|
|
162
|
+
class WorkerRoleSpec:
|
|
163
|
+
id: str
|
|
164
|
+
owner_app: str
|
|
165
|
+
tool_name: str
|
|
166
|
+
kind: str = "worker.role"
|
|
167
|
+
api_version: str = "v1"
|
|
168
|
+
priority: int = 100
|
|
169
|
+
title: str = ""
|
|
170
|
+
name: str = ""
|
|
171
|
+
auto_start: bool = False
|
|
172
|
+
auto_start_setting: str = ""
|
|
173
|
+
restart: str = "always"
|
|
174
|
+
worker_kind: str = "infrastructure_worker"
|
|
175
|
+
replica_count_setting: str = ""
|
|
176
|
+
description: str = ""
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@dataclass(frozen=True, slots=True)
|
|
180
|
+
class CliInvocationContext:
|
|
181
|
+
project: Any
|
|
182
|
+
args: Any
|
|
183
|
+
stdout: Any
|
|
184
|
+
stderr: Any
|
|
185
|
+
plan: Any | None = None
|
|
186
|
+
app_id: str = ""
|
|
187
|
+
tool_name: str = ""
|
|
188
|
+
argv: tuple[str, ...] = ()
|
|
189
|
+
remainder: tuple[str, ...] = ()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@dataclass(frozen=True, slots=True)
|
|
193
|
+
class CliToolSpec:
|
|
194
|
+
id: str
|
|
195
|
+
owner_app: str
|
|
196
|
+
command: tuple[str, ...]
|
|
197
|
+
summary: str
|
|
198
|
+
tool: Any
|
|
199
|
+
kind: str = "cli.tool"
|
|
200
|
+
api_version: str = "v1"
|
|
201
|
+
priority: int = 100
|
|
202
|
+
title: str = ""
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@dataclass(frozen=True, slots=True)
|
|
206
|
+
class PageProfileProviderSpec:
|
|
207
|
+
id: str
|
|
208
|
+
owner_app: str
|
|
209
|
+
provider: Any
|
|
210
|
+
kind: str = "page.profile_provider"
|
|
211
|
+
api_version: str = "v1"
|
|
212
|
+
priority: int = 100
|
|
213
|
+
title: str = ""
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@dataclass(frozen=True, slots=True)
|
|
217
|
+
class ResourceContributionSpec:
|
|
218
|
+
id: str
|
|
219
|
+
owner_app: str
|
|
220
|
+
templates_dir: str = "templates"
|
|
221
|
+
static_dir: str = "static"
|
|
222
|
+
locales_dir: str = "locales"
|
|
223
|
+
migrations_dir: str = "migrations"
|
|
224
|
+
kind: str = "resource.contribution"
|
|
225
|
+
api_version: str = "v1"
|
|
226
|
+
priority: int = 100
|
|
227
|
+
title: str = ""
|
|
228
|
+
locale_bundles: tuple[dict[str, Any], ...] = ()
|
|
229
|
+
locale_dependencies: tuple[dict[str, Any], ...] = ()
|
|
230
|
+
locale_consumer_bindings: tuple[dict[str, Any], ...] = ()
|
|
231
|
+
locale_profiles: tuple[dict[str, Any], ...] = ()
|
|
232
|
+
locale_overrides: tuple[dict[str, Any], ...] = ()
|
|
233
|
+
locale_allowlist: tuple[str, ...] = ()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@dataclass(frozen=True, slots=True)
|
|
237
|
+
class ProtocolRegistrationSpec:
|
|
238
|
+
id: str
|
|
239
|
+
owner_app: str
|
|
240
|
+
protocol_kind: str
|
|
241
|
+
spec_name: str
|
|
242
|
+
runtime_owner: str
|
|
243
|
+
required_fields: tuple[str, ...] = ()
|
|
244
|
+
string_fields: tuple[str, ...] = ()
|
|
245
|
+
import_fields: tuple[str, ...] = ()
|
|
246
|
+
callable_fields: tuple[str, ...] = ()
|
|
247
|
+
validator: Any | None = None
|
|
248
|
+
kind: str = "protocol.registration"
|
|
249
|
+
api_version: str = "v1"
|
|
250
|
+
priority: int = 100
|
|
251
|
+
title: str = ""
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
@dataclass(frozen=True, slots=True)
|
|
255
|
+
class ProtocolExtensionSpec:
|
|
256
|
+
id: str
|
|
257
|
+
owner_app: str
|
|
258
|
+
kind: str
|
|
259
|
+
fields: dict[str, Any] = field(default_factory=dict)
|
|
260
|
+
optional: bool = False
|
|
261
|
+
api_version: str = "v1"
|
|
262
|
+
priority: int = 100
|
|
263
|
+
title: str = ""
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
FormalExtensionSpec: TypeAlias = (
|
|
267
|
+
ExtensionSpec
|
|
268
|
+
| HostBuilderSpec
|
|
269
|
+
| SettingsProviderSpec
|
|
270
|
+
| InfraProviderSpec
|
|
271
|
+
| RuntimeManifestContributionSpec
|
|
272
|
+
| LifecycleContributionSpec
|
|
273
|
+
| WorkerRoleSpec
|
|
274
|
+
| CliToolSpec
|
|
275
|
+
| PageProfileProviderSpec
|
|
276
|
+
| ResourceContributionSpec
|
|
277
|
+
| ProtocolRegistrationSpec
|
|
278
|
+
| ProtocolExtensionSpec
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
@dataclass(frozen=True, slots=True)
|
|
283
|
+
class ExtensionRegistry:
|
|
284
|
+
extensions: tuple[FormalExtensionSpec, ...] = ()
|
|
285
|
+
|
|
286
|
+
def by_id(self) -> dict[str, FormalExtensionSpec]:
|
|
287
|
+
return {str(extension.id): extension for extension in self.extensions}
|
|
288
|
+
|
|
289
|
+
def by_kind(self, kind: str) -> tuple[FormalExtensionSpec, ...]:
|
|
290
|
+
expected = str(kind or "").strip()
|
|
291
|
+
if not expected:
|
|
292
|
+
return ()
|
|
293
|
+
return tuple(extension for extension in self.extensions if extension.kind == expected)
|
|
294
|
+
|
|
295
|
+
def validate(self) -> None:
|
|
296
|
+
registered_protocols: dict[str, ProtocolRegistrationSpec] = {}
|
|
297
|
+
protocol_extensions: list[ProtocolExtensionSpec] = []
|
|
298
|
+
ids: list[str] = []
|
|
299
|
+
for extension in self.extensions:
|
|
300
|
+
raw_id = getattr(extension, "id", None)
|
|
301
|
+
if not isinstance(raw_id, str) or not raw_id.strip():
|
|
302
|
+
raise PzError(
|
|
303
|
+
code="PZ_EXTENSION_ID_INVALID",
|
|
304
|
+
message="Extension id must be a non-empty string.",
|
|
305
|
+
stage="extensions",
|
|
306
|
+
owner="core.extensions",
|
|
307
|
+
action="validate",
|
|
308
|
+
)
|
|
309
|
+
raw_owner = getattr(extension, "owner_app", None)
|
|
310
|
+
if not isinstance(raw_owner, str) or not raw_owner.strip():
|
|
311
|
+
raise PzError(
|
|
312
|
+
code="PZ_EXTENSION_OWNER_INVALID",
|
|
313
|
+
message=f"Extension '{raw_id}' must declare owner_app as a non-empty string.",
|
|
314
|
+
stage="extensions",
|
|
315
|
+
owner=str(raw_id),
|
|
316
|
+
action="validate",
|
|
317
|
+
)
|
|
318
|
+
raw_kind = getattr(extension, "kind", None)
|
|
319
|
+
if not isinstance(raw_kind, str) or not raw_kind.strip():
|
|
320
|
+
raise PzError(
|
|
321
|
+
code="PZ_EXTENSION_KIND_INVALID",
|
|
322
|
+
message=f"Extension '{raw_id}' must declare kind as a non-empty string.",
|
|
323
|
+
stage="extensions",
|
|
324
|
+
owner=str(raw_owner),
|
|
325
|
+
action="validate",
|
|
326
|
+
)
|
|
327
|
+
provides = getattr(extension, "provides", ())
|
|
328
|
+
if provides not in (None, ()) and not isinstance(provides, tuple):
|
|
329
|
+
raise PzError(
|
|
330
|
+
code="PZ_EXTENSION_PROVIDES_INVALID",
|
|
331
|
+
message=f"Extension '{raw_id}' must declare provides as a tuple of non-empty strings.",
|
|
332
|
+
stage="extensions",
|
|
333
|
+
owner=str(raw_owner),
|
|
334
|
+
action="validate",
|
|
335
|
+
)
|
|
336
|
+
for item in tuple(provides or ()):
|
|
337
|
+
if not isinstance(item, str) or not item.strip():
|
|
338
|
+
raise PzError(
|
|
339
|
+
code="PZ_EXTENSION_PROVIDES_ITEM_INVALID",
|
|
340
|
+
message=f"Extension '{raw_id}' provides contains an invalid item.",
|
|
341
|
+
stage="extensions",
|
|
342
|
+
owner=str(raw_owner),
|
|
343
|
+
action="validate",
|
|
344
|
+
)
|
|
345
|
+
if isinstance(extension, WorkerRoleSpec):
|
|
346
|
+
if not isinstance(extension.tool_name, str) or not extension.tool_name.strip():
|
|
347
|
+
raise PzError(
|
|
348
|
+
code="PZ_WORKER_ROLE_TOOL_INVALID",
|
|
349
|
+
message=f"Worker role '{raw_id}' must declare tool_name as a non-empty string.",
|
|
350
|
+
stage="extensions",
|
|
351
|
+
owner=str(raw_owner),
|
|
352
|
+
action="validate",
|
|
353
|
+
)
|
|
354
|
+
if extension.restart not in {"always", "never"}:
|
|
355
|
+
raise PzError(
|
|
356
|
+
code="PZ_WORKER_ROLE_RESTART_INVALID",
|
|
357
|
+
message=f"Worker role '{raw_id}' restart must be `always` or `never`.",
|
|
358
|
+
stage="extensions",
|
|
359
|
+
owner=str(raw_owner),
|
|
360
|
+
action="validate",
|
|
361
|
+
)
|
|
362
|
+
if (
|
|
363
|
+
not isinstance(extension.worker_kind, str)
|
|
364
|
+
or extension.worker_kind not in WORKER_ROLE_KINDS
|
|
365
|
+
):
|
|
366
|
+
raise PzError(
|
|
367
|
+
code="PZ_WORKER_ROLE_KIND_INVALID",
|
|
368
|
+
message=(
|
|
369
|
+
f"Worker role '{raw_id}' worker_kind must be one of: "
|
|
370
|
+
f"{', '.join(sorted(WORKER_ROLE_KINDS))}."
|
|
371
|
+
),
|
|
372
|
+
stage="extensions",
|
|
373
|
+
owner=str(raw_owner),
|
|
374
|
+
action="validate",
|
|
375
|
+
)
|
|
376
|
+
if (
|
|
377
|
+
extension.auto_start_setting
|
|
378
|
+
and (
|
|
379
|
+
not isinstance(extension.auto_start_setting, str)
|
|
380
|
+
or not extension.auto_start_setting.strip()
|
|
381
|
+
)
|
|
382
|
+
):
|
|
383
|
+
raise PzError(
|
|
384
|
+
code="PZ_WORKER_ROLE_AUTO_START_SETTING_INVALID",
|
|
385
|
+
message=(
|
|
386
|
+
f"Worker role '{raw_id}' auto_start_setting must be empty or "
|
|
387
|
+
"a non-empty string."
|
|
388
|
+
),
|
|
389
|
+
stage="extensions",
|
|
390
|
+
owner=str(raw_owner),
|
|
391
|
+
action="validate",
|
|
392
|
+
)
|
|
393
|
+
if (
|
|
394
|
+
extension.replica_count_setting
|
|
395
|
+
and (
|
|
396
|
+
not isinstance(extension.replica_count_setting, str)
|
|
397
|
+
or not extension.replica_count_setting.strip()
|
|
398
|
+
)
|
|
399
|
+
):
|
|
400
|
+
raise PzError(
|
|
401
|
+
code="PZ_WORKER_ROLE_REPLICA_COUNT_SETTING_INVALID",
|
|
402
|
+
message=(
|
|
403
|
+
f"Worker role '{raw_id}' replica_count_setting must be empty or "
|
|
404
|
+
"a non-empty string."
|
|
405
|
+
),
|
|
406
|
+
stage="extensions",
|
|
407
|
+
owner=str(raw_owner),
|
|
408
|
+
action="validate",
|
|
409
|
+
)
|
|
410
|
+
if isinstance(extension, ExtensionSpec):
|
|
411
|
+
payload = extension.payload
|
|
412
|
+
if not isinstance(payload, dict):
|
|
413
|
+
raise PzError(
|
|
414
|
+
code="PZ_EXTENSION_PAYLOAD_INVALID",
|
|
415
|
+
message=f"Extension '{raw_id}' payload must be a dict.",
|
|
416
|
+
stage="extensions",
|
|
417
|
+
owner=str(raw_owner),
|
|
418
|
+
action="validate",
|
|
419
|
+
)
|
|
420
|
+
if not _is_declarative_payload_value(payload):
|
|
421
|
+
raise PzError(
|
|
422
|
+
code="PZ_EXTENSION_PAYLOAD_NOT_DECLARATIVE",
|
|
423
|
+
message=(
|
|
424
|
+
f"Extension '{raw_id}' payload must be declarative data only. "
|
|
425
|
+
"Use import strings for runtime objects such as routers, providers, "
|
|
426
|
+
"handlers, or factories."
|
|
427
|
+
),
|
|
428
|
+
stage="extensions",
|
|
429
|
+
owner=str(raw_owner),
|
|
430
|
+
action="validate",
|
|
431
|
+
)
|
|
432
|
+
if isinstance(extension, RuntimeManifestContributionSpec):
|
|
433
|
+
if str(extension.kind or "").strip() != "runtime.manifest_contribution":
|
|
434
|
+
raise PzError(
|
|
435
|
+
code="PZ_RUNTIME_MANIFEST_CONTRIBUTION_KIND_INVALID",
|
|
436
|
+
message=f"Runtime manifest contribution '{raw_id}' kind must be `runtime.manifest_contribution`.",
|
|
437
|
+
stage="extensions",
|
|
438
|
+
owner=str(raw_owner),
|
|
439
|
+
action="validate",
|
|
440
|
+
)
|
|
441
|
+
provider = extension.provider
|
|
442
|
+
if provider is None:
|
|
443
|
+
raise PzError(
|
|
444
|
+
code="PZ_RUNTIME_MANIFEST_CONTRIBUTION_PROVIDER_INVALID",
|
|
445
|
+
message=f"Runtime manifest contribution '{raw_id}' must declare a provider.",
|
|
446
|
+
stage="extensions",
|
|
447
|
+
owner=str(raw_owner),
|
|
448
|
+
action="validate",
|
|
449
|
+
)
|
|
450
|
+
if isinstance(provider, str) and not provider.strip():
|
|
451
|
+
raise PzError(
|
|
452
|
+
code="PZ_RUNTIME_MANIFEST_CONTRIBUTION_PROVIDER_INVALID",
|
|
453
|
+
message=(
|
|
454
|
+
f"Runtime manifest contribution '{raw_id}' must declare provider as "
|
|
455
|
+
"a non-empty string."
|
|
456
|
+
),
|
|
457
|
+
stage="extensions",
|
|
458
|
+
owner=str(raw_owner),
|
|
459
|
+
action="validate",
|
|
460
|
+
)
|
|
461
|
+
if isinstance(extension, CliToolSpec):
|
|
462
|
+
if str(extension.kind or "").strip() != "cli.tool":
|
|
463
|
+
raise PzError(
|
|
464
|
+
code="PZ_CLI_TOOL_KIND_INVALID",
|
|
465
|
+
message=f"CLI tool '{raw_id}' kind must be `cli.tool`.",
|
|
466
|
+
stage="extensions",
|
|
467
|
+
owner=str(raw_owner),
|
|
468
|
+
action="validate",
|
|
469
|
+
)
|
|
470
|
+
if not isinstance(extension.command, tuple) or not extension.command:
|
|
471
|
+
raise PzError(
|
|
472
|
+
code="PZ_CLI_TOOL_COMMAND_INVALID",
|
|
473
|
+
message=f"CLI tool '{raw_id}' must declare command as a non-empty tuple.",
|
|
474
|
+
stage="extensions",
|
|
475
|
+
owner=str(raw_owner),
|
|
476
|
+
action="validate",
|
|
477
|
+
)
|
|
478
|
+
for part in extension.command:
|
|
479
|
+
if not isinstance(part, str) or not part.strip():
|
|
480
|
+
raise PzError(
|
|
481
|
+
code="PZ_CLI_TOOL_COMMAND_INVALID",
|
|
482
|
+
message=f"CLI tool '{raw_id}' command contains an invalid segment.",
|
|
483
|
+
stage="extensions",
|
|
484
|
+
owner=str(raw_owner),
|
|
485
|
+
action="validate",
|
|
486
|
+
)
|
|
487
|
+
tool = extension.tool
|
|
488
|
+
if not callable(getattr(tool, "configure", None)) or not callable(getattr(tool, "run", None)):
|
|
489
|
+
raise PzError(
|
|
490
|
+
code="PZ_CLI_TOOL_OBJECT_INVALID",
|
|
491
|
+
message=f"CLI tool '{raw_id}' must expose configure(parser) and run(ctx).",
|
|
492
|
+
stage="extensions",
|
|
493
|
+
owner=str(raw_owner),
|
|
494
|
+
action="validate",
|
|
495
|
+
)
|
|
496
|
+
if isinstance(extension, PageProfileProviderSpec):
|
|
497
|
+
provider = extension.provider
|
|
498
|
+
if provider is None:
|
|
499
|
+
raise PzError(
|
|
500
|
+
code="PZ_PAGE_PROFILE_PROVIDER_INVALID",
|
|
501
|
+
message=f"Page-profile provider '{raw_id}' must declare a provider.",
|
|
502
|
+
stage="extensions",
|
|
503
|
+
owner=str(raw_owner),
|
|
504
|
+
action="validate",
|
|
505
|
+
)
|
|
506
|
+
if isinstance(provider, str) and not provider.strip():
|
|
507
|
+
raise PzError(
|
|
508
|
+
code="PZ_PAGE_PROFILE_PROVIDER_INVALID",
|
|
509
|
+
message=f"Page-profile provider '{raw_id}' must declare provider as a non-empty string.",
|
|
510
|
+
stage="extensions",
|
|
511
|
+
owner=str(raw_owner),
|
|
512
|
+
action="validate",
|
|
513
|
+
)
|
|
514
|
+
if isinstance(extension, ResourceContributionSpec):
|
|
515
|
+
if str(extension.kind or "").strip() != "resource.contribution":
|
|
516
|
+
raise PzError(
|
|
517
|
+
code="PZ_RESOURCE_CONTRIBUTION_KIND_INVALID",
|
|
518
|
+
message=f"Resource contribution '{raw_id}' kind must be `resource.contribution`.",
|
|
519
|
+
stage="extensions",
|
|
520
|
+
owner=str(raw_owner),
|
|
521
|
+
action="validate",
|
|
522
|
+
)
|
|
523
|
+
for field_name in ("templates_dir", "static_dir", "locales_dir", "migrations_dir"):
|
|
524
|
+
value = getattr(extension, field_name)
|
|
525
|
+
if not isinstance(value, str) or not value.strip():
|
|
526
|
+
raise PzError(
|
|
527
|
+
code="PZ_RESOURCE_CONTRIBUTION_FIELD_INVALID",
|
|
528
|
+
message=(
|
|
529
|
+
f"Resource contribution '{raw_id}' field '{field_name}' "
|
|
530
|
+
"must be a non-empty string."
|
|
531
|
+
),
|
|
532
|
+
stage="extensions",
|
|
533
|
+
owner=str(raw_owner),
|
|
534
|
+
action="validate",
|
|
535
|
+
)
|
|
536
|
+
for attr_name in (
|
|
537
|
+
"locale_bundles",
|
|
538
|
+
"locale_dependencies",
|
|
539
|
+
"locale_consumer_bindings",
|
|
540
|
+
"locale_profiles",
|
|
541
|
+
"locale_overrides",
|
|
542
|
+
):
|
|
543
|
+
value = getattr(extension, attr_name)
|
|
544
|
+
if value not in (None, ()) and not isinstance(value, tuple):
|
|
545
|
+
raise PzError(
|
|
546
|
+
code="PZ_RESOURCE_CONTRIBUTION_FIELD_INVALID",
|
|
547
|
+
message=(
|
|
548
|
+
f"Resource contribution '{raw_id}' field '{attr_name}' must be a tuple."
|
|
549
|
+
),
|
|
550
|
+
stage="extensions",
|
|
551
|
+
owner=str(raw_owner),
|
|
552
|
+
action="validate",
|
|
553
|
+
)
|
|
554
|
+
if extension.locale_allowlist not in (None, ()) and not isinstance(extension.locale_allowlist, tuple):
|
|
555
|
+
raise PzError(
|
|
556
|
+
code="PZ_RESOURCE_CONTRIBUTION_FIELD_INVALID",
|
|
557
|
+
message=(
|
|
558
|
+
f"Resource contribution '{raw_id}' field 'locale_allowlist' must be a tuple."
|
|
559
|
+
),
|
|
560
|
+
stage="extensions",
|
|
561
|
+
owner=str(raw_owner),
|
|
562
|
+
action="validate",
|
|
563
|
+
)
|
|
564
|
+
for item in tuple(extension.locale_allowlist or ()):
|
|
565
|
+
if not isinstance(item, str) or not item.strip():
|
|
566
|
+
raise PzError(
|
|
567
|
+
code="PZ_RESOURCE_CONTRIBUTION_FIELD_INVALID",
|
|
568
|
+
message=(
|
|
569
|
+
f"Resource contribution '{raw_id}' field 'locale_allowlist' contains an invalid item."
|
|
570
|
+
),
|
|
571
|
+
stage="extensions",
|
|
572
|
+
owner=str(raw_owner),
|
|
573
|
+
action="validate",
|
|
574
|
+
)
|
|
575
|
+
if isinstance(extension, ProtocolRegistrationSpec):
|
|
576
|
+
if str(extension.kind or "").strip() != "protocol.registration":
|
|
577
|
+
raise PzError(
|
|
578
|
+
code="PZ_PROTOCOL_REGISTRATION_KIND_INVALID",
|
|
579
|
+
message=f"Protocol registration '{raw_id}' kind must be `protocol.registration`.",
|
|
580
|
+
stage="extensions",
|
|
581
|
+
owner=str(raw_owner),
|
|
582
|
+
action="validate",
|
|
583
|
+
)
|
|
584
|
+
protocol_kind = str(extension.protocol_kind or "").strip()
|
|
585
|
+
if not protocol_kind:
|
|
586
|
+
raise PzError(
|
|
587
|
+
code="PZ_PROTOCOL_KIND_INVALID",
|
|
588
|
+
message=f"Protocol registration '{raw_id}' must declare protocol_kind.",
|
|
589
|
+
stage="extensions",
|
|
590
|
+
owner=str(raw_owner),
|
|
591
|
+
action="validate",
|
|
592
|
+
)
|
|
593
|
+
if protocol_kind in registered_protocols:
|
|
594
|
+
raise PzError(
|
|
595
|
+
code="PZ_PROTOCOL_KIND_DUPLICATE",
|
|
596
|
+
message=f"Protocol kind '{protocol_kind}' is registered more than once.",
|
|
597
|
+
stage="extensions",
|
|
598
|
+
owner=str(raw_owner),
|
|
599
|
+
action="validate",
|
|
600
|
+
)
|
|
601
|
+
if not isinstance(extension.spec_name, str) or not extension.spec_name.strip():
|
|
602
|
+
raise PzError(
|
|
603
|
+
code="PZ_PROTOCOL_SPEC_NAME_INVALID",
|
|
604
|
+
message=f"Protocol registration '{raw_id}' must declare spec_name.",
|
|
605
|
+
stage="extensions",
|
|
606
|
+
owner=str(raw_owner),
|
|
607
|
+
action="validate",
|
|
608
|
+
)
|
|
609
|
+
if not isinstance(extension.runtime_owner, str) or not extension.runtime_owner.strip():
|
|
610
|
+
raise PzError(
|
|
611
|
+
code="PZ_PROTOCOL_RUNTIME_OWNER_INVALID",
|
|
612
|
+
message=f"Protocol registration '{raw_id}' must declare runtime_owner.",
|
|
613
|
+
stage="extensions",
|
|
614
|
+
owner=str(raw_owner),
|
|
615
|
+
action="validate",
|
|
616
|
+
)
|
|
617
|
+
for attr_name, code in (
|
|
618
|
+
("required_fields", "PZ_PROTOCOL_REQUIRED_FIELDS_INVALID"),
|
|
619
|
+
("string_fields", "PZ_PROTOCOL_STRING_FIELDS_INVALID"),
|
|
620
|
+
("import_fields", "PZ_PROTOCOL_IMPORT_FIELDS_INVALID"),
|
|
621
|
+
("callable_fields", "PZ_PROTOCOL_CALLABLE_FIELDS_INVALID"),
|
|
622
|
+
):
|
|
623
|
+
value = getattr(extension, attr_name, ())
|
|
624
|
+
if value not in (None, ()) and not isinstance(value, tuple):
|
|
625
|
+
raise PzError(
|
|
626
|
+
code=code,
|
|
627
|
+
message=f"Protocol registration '{raw_id}' must declare {attr_name} as a tuple.",
|
|
628
|
+
stage="extensions",
|
|
629
|
+
owner=str(raw_owner),
|
|
630
|
+
action="validate",
|
|
631
|
+
)
|
|
632
|
+
for item in tuple(value or ()):
|
|
633
|
+
if not isinstance(item, str) or not item.strip():
|
|
634
|
+
raise PzError(
|
|
635
|
+
code=code,
|
|
636
|
+
message=f"Protocol registration '{raw_id}' contains an invalid {attr_name} item.",
|
|
637
|
+
stage="extensions",
|
|
638
|
+
owner=str(raw_owner),
|
|
639
|
+
action="validate",
|
|
640
|
+
)
|
|
641
|
+
validator = extension.validator
|
|
642
|
+
if validator is not None and not (
|
|
643
|
+
callable(validator) or (isinstance(validator, str) and validator.strip())
|
|
644
|
+
):
|
|
645
|
+
raise PzError(
|
|
646
|
+
code="PZ_PROTOCOL_VALIDATOR_INVALID",
|
|
647
|
+
message=f"Protocol registration '{raw_id}' validator must be callable or a non-empty string.",
|
|
648
|
+
stage="extensions",
|
|
649
|
+
owner=str(raw_owner),
|
|
650
|
+
action="validate",
|
|
651
|
+
)
|
|
652
|
+
registered_protocols[protocol_kind] = extension
|
|
653
|
+
if isinstance(extension, ProtocolExtensionSpec):
|
|
654
|
+
protocol_extensions.append(extension)
|
|
655
|
+
ids.append(raw_id)
|
|
656
|
+
if len(ids) != len(set(ids)):
|
|
657
|
+
raise PzError(
|
|
658
|
+
code="PZ_EXTENSION_DUPLICATE_ID",
|
|
659
|
+
message="ExtensionRegistry contains duplicate extension ids.",
|
|
660
|
+
stage="extensions",
|
|
661
|
+
owner="core.extensions",
|
|
662
|
+
action="validate",
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
for extension in self.extensions:
|
|
666
|
+
if isinstance(extension, ExtensionSpec) and extension.kind in registered_protocols:
|
|
667
|
+
raise PzError(
|
|
668
|
+
code="PZ_PROTOCOL_EXTENSION_SPEC_REQUIRED",
|
|
669
|
+
message=(
|
|
670
|
+
f"Extension '{extension.id}' kind '{extension.kind}' is a registered protocol and "
|
|
671
|
+
"must use ProtocolExtensionSpec."
|
|
672
|
+
),
|
|
673
|
+
stage="extensions",
|
|
674
|
+
owner=extension.owner_app,
|
|
675
|
+
action="validate",
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
for extension in protocol_extensions:
|
|
679
|
+
raw_id = str(extension.id or "").strip()
|
|
680
|
+
raw_owner = str(extension.owner_app or "").strip()
|
|
681
|
+
protocol = registered_protocols.get(str(extension.kind or "").strip())
|
|
682
|
+
if protocol is None:
|
|
683
|
+
if extension.optional:
|
|
684
|
+
continue
|
|
685
|
+
raise PzError(
|
|
686
|
+
code="PZ_PROTOCOL_EXTENSION_UNREGISTERED",
|
|
687
|
+
message=f"Protocol extension '{raw_id}' declares unknown kind '{extension.kind}'.",
|
|
688
|
+
stage="extensions",
|
|
689
|
+
owner=str(raw_owner),
|
|
690
|
+
action="validate",
|
|
691
|
+
)
|
|
692
|
+
if not isinstance(extension.fields, dict):
|
|
693
|
+
raise PzError(
|
|
694
|
+
code="PZ_PROTOCOL_FIELDS_INVALID",
|
|
695
|
+
message=f"Protocol extension '{raw_id}' must declare fields as a dict.",
|
|
696
|
+
stage="extensions",
|
|
697
|
+
owner=str(raw_owner),
|
|
698
|
+
action="validate",
|
|
699
|
+
)
|
|
700
|
+
for field_name in protocol.required_fields:
|
|
701
|
+
if field_name not in extension.fields:
|
|
702
|
+
raise PzError(
|
|
703
|
+
code="PZ_PROTOCOL_REQUIRED_FIELD_MISSING",
|
|
704
|
+
message=f"Protocol extension '{raw_id}' is missing required field '{field_name}'.",
|
|
705
|
+
stage="extensions",
|
|
706
|
+
owner=str(raw_owner),
|
|
707
|
+
action="validate",
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
for field_name in protocol.string_fields:
|
|
711
|
+
value = extension.fields.get(field_name)
|
|
712
|
+
if not isinstance(value, str) or not value.strip():
|
|
713
|
+
raise PzError(
|
|
714
|
+
code="PZ_PROTOCOL_STRING_FIELD_INVALID",
|
|
715
|
+
message=f"Protocol extension '{raw_id}' field '{field_name}' must be a non-empty string.",
|
|
716
|
+
stage="extensions",
|
|
717
|
+
owner=str(raw_owner),
|
|
718
|
+
action="validate",
|
|
719
|
+
)
|
|
720
|
+
validator = protocol.validator
|
|
721
|
+
if validator is not None:
|
|
722
|
+
validator_callable = _instantiate_extension_target(validator)
|
|
723
|
+
if not callable(validator_callable):
|
|
724
|
+
raise PzError(
|
|
725
|
+
code="PZ_PROTOCOL_VALIDATOR_INVALID",
|
|
726
|
+
message=f"Protocol registration '{protocol.id}' validator must resolve to callable.",
|
|
727
|
+
stage="extensions",
|
|
728
|
+
owner=str(raw_owner),
|
|
729
|
+
action="validate",
|
|
730
|
+
)
|
|
731
|
+
validator_callable(extension)
|
|
732
|
+
for field_name in protocol.import_fields:
|
|
733
|
+
value = extension.fields.get(field_name)
|
|
734
|
+
if not isinstance(value, str) or not value.strip():
|
|
735
|
+
raise PzError(
|
|
736
|
+
code="PZ_PROTOCOL_IMPORT_FIELD_INVALID",
|
|
737
|
+
message=f"Protocol extension '{raw_id}' field '{field_name}' must be a non-empty import string.",
|
|
738
|
+
stage="extensions",
|
|
739
|
+
owner=str(raw_owner),
|
|
740
|
+
action="validate",
|
|
741
|
+
)
|
|
742
|
+
try:
|
|
743
|
+
_instantiate_extension_target(value)
|
|
744
|
+
except Exception as exc:
|
|
745
|
+
raise PzError(
|
|
746
|
+
code="PZ_PROTOCOL_IMPORT_RESOLVE_FAILED",
|
|
747
|
+
message=(
|
|
748
|
+
f"Protocol extension '{raw_id}' field '{field_name}' failed to load during "
|
|
749
|
+
f"validation: {exc}"
|
|
750
|
+
),
|
|
751
|
+
stage="extensions",
|
|
752
|
+
owner=str(raw_owner),
|
|
753
|
+
action="validate",
|
|
754
|
+
) from exc
|
|
755
|
+
for field_name in protocol.callable_fields:
|
|
756
|
+
value = extension.fields.get(field_name)
|
|
757
|
+
if value is None:
|
|
758
|
+
raise PzError(
|
|
759
|
+
code="PZ_PROTOCOL_CALLABLE_FIELD_INVALID",
|
|
760
|
+
message=f"Protocol extension '{raw_id}' field '{field_name}' must be callable.",
|
|
761
|
+
stage="extensions",
|
|
762
|
+
owner=str(raw_owner),
|
|
763
|
+
action="validate",
|
|
764
|
+
)
|
|
765
|
+
if not callable(_instantiate_extension_target(value)):
|
|
766
|
+
raise PzError(
|
|
767
|
+
code="PZ_PROTOCOL_CALLABLE_FIELD_INVALID",
|
|
768
|
+
message=f"Protocol extension '{raw_id}' field '{field_name}' must resolve to callable.",
|
|
769
|
+
stage="extensions",
|
|
770
|
+
owner=str(raw_owner),
|
|
771
|
+
action="validate",
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
installed = self.by_id()
|
|
775
|
+
for extension in self.extensions:
|
|
776
|
+
conflicts = tuple(getattr(extension, "conflicts", ()) or ())
|
|
777
|
+
owner_app = str(getattr(extension, "owner_app", "") or "")
|
|
778
|
+
extension_id = str(getattr(extension, "id", "") or "")
|
|
779
|
+
for conflict in conflicts:
|
|
780
|
+
if conflict in installed:
|
|
781
|
+
raise PzError(
|
|
782
|
+
code="PZ_EXTENSION_CONFLICT",
|
|
783
|
+
message=(
|
|
784
|
+
f"Extension '{extension_id}' conflicts with installed "
|
|
785
|
+
f"extension '{conflict}'."
|
|
786
|
+
),
|
|
787
|
+
stage="extensions",
|
|
788
|
+
owner=owner_app or extension_id,
|
|
789
|
+
action="validate",
|
|
790
|
+
)
|