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.
Files changed (399) hide show
  1. pz_cli-5.0.0.dist-info/METADATA +51 -0
  2. pz_cli-5.0.0.dist-info/RECORD +399 -0
  3. pz_cli-5.0.0.dist-info/WHEEL +4 -0
  4. pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
  5. pz_core/__init__.py +64 -0
  6. pz_core/__main__.py +7 -0
  7. pz_core/app.py +45 -0
  8. pz_core/assembly/__init__.py +17 -0
  9. pz_core/assembly/app_discovery.py +1240 -0
  10. pz_core/assembly/apps/__init__.py +25 -0
  11. pz_core/assembly/apps/compiler.py +824 -0
  12. pz_core/assembly/apps/providers.py +188 -0
  13. pz_core/assembly/cli/__init__.py +9 -0
  14. pz_core/assembly/cli/compiler.py +166 -0
  15. pz_core/assembly/diagnostics/__init__.py +21 -0
  16. pz_core/assembly/diagnostics/checks.py +257 -0
  17. pz_core/assembly/diagnostics/dev_sources.py +569 -0
  18. pz_core/assembly/events/__init__.py +5 -0
  19. pz_core/assembly/events/compiler.py +219 -0
  20. pz_core/assembly/extensions/__init__.py +5 -0
  21. pz_core/assembly/extensions/compiler.py +696 -0
  22. pz_core/assembly/infra/__init__.py +6 -0
  23. pz_core/assembly/infra/compiler.py +272 -0
  24. pz_core/assembly/lifecycle/__init__.py +5 -0
  25. pz_core/assembly/lifecycle/compiler.py +95 -0
  26. pz_core/assembly/middlewares/__init__.py +19 -0
  27. pz_core/assembly/middlewares/compiler.py +508 -0
  28. pz_core/assembly/project/__init__.py +7 -0
  29. pz_core/assembly/project/compiler.py +9 -0
  30. pz_core/assembly/project/context.py +17 -0
  31. pz_core/assembly/project/discovery.py +227 -0
  32. pz_core/assembly/resources/__init__.py +19 -0
  33. pz_core/assembly/resources/compiler.py +310 -0
  34. pz_core/assembly/resources/settings.py +129 -0
  35. pz_core/assembly/routes/__init__.py +7 -0
  36. pz_core/assembly/routes/compiler.py +400 -0
  37. pz_core/assembly/runtime_manifests/__init__.py +13 -0
  38. pz_core/assembly/runtime_manifests/compiler.py +159 -0
  39. pz_core/assembly/settings/__init__.py +17 -0
  40. pz_core/assembly/settings/compiler.py +786 -0
  41. pz_core/assembly/settings/host_project_overrides.py +82 -0
  42. pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
  43. pz_core/authoring/__init__.py +79 -0
  44. pz_core/authoring/app_init_service.py +946 -0
  45. pz_core/authoring/app_versions.py +814 -0
  46. pz_core/authoring/cli.py +192 -0
  47. pz_core/authoring/commands.py +1810 -0
  48. pz_core/authoring/conflicts.py +180 -0
  49. pz_core/authoring/dev_bindings.py +916 -0
  50. pz_core/authoring/dev_git.py +1087 -0
  51. pz_core/authoring/dev_import.py +1061 -0
  52. pz_core/authoring/dev_manifest.py +522 -0
  53. pz_core/authoring/dev_sources.py +1638 -0
  54. pz_core/authoring/env_cli.py +454 -0
  55. pz_core/authoring/files.py +109 -0
  56. pz_core/authoring/ide_projection.py +1129 -0
  57. pz_core/authoring/naming.py +58 -0
  58. pz_core/authoring/official_dev_sources.py +432 -0
  59. pz_core/authoring/official_sources.json +156 -0
  60. pz_core/authoring/orchestration_service.py +558 -0
  61. pz_core/authoring/project_default.jsonc +53 -0
  62. pz_core/authoring/project_defaults.py +88 -0
  63. pz_core/authoring/project_metadata_service.py +199 -0
  64. pz_core/authoring/project_settings_checks.py +51 -0
  65. pz_core/authoring/project_settings_cli.py +299 -0
  66. pz_core/authoring/project_settings_service.py +1700 -0
  67. pz_core/authoring/project_state.py +399 -0
  68. pz_core/authoring/publish_git.py +423 -0
  69. pz_core/authoring/publish_lock.py +188 -0
  70. pz_core/authoring/publish_source.py +195 -0
  71. pz_core/authoring/release.py +1382 -0
  72. pz_core/authoring/repo_keys.py +29 -0
  73. pz_core/authoring/root_cli.py +28 -0
  74. pz_core/authoring/scaffold_service.py +325 -0
  75. pz_core/authoring/sync_service.py +787 -0
  76. pz_core/authoring/templates/app/__init__.py +1 -0
  77. pz_core/authoring/templates/app/api.py +25 -0
  78. pz_core/authoring/templates/app/apps.py +31 -0
  79. pz_core/authoring/templates/app/auth_package_init.py +14 -0
  80. pz_core/authoring/templates/app/auth_readme.py +29 -0
  81. pz_core/authoring/templates/app/configs_package_init.py +14 -0
  82. pz_core/authoring/templates/app/default_env.py +18 -0
  83. pz_core/authoring/templates/app/default_jsonc.py +25 -0
  84. pz_core/authoring/templates/app/locales_readme.py +25 -0
  85. pz_core/authoring/templates/app/migrations_readme.py +19 -0
  86. pz_core/authoring/templates/app/models.py +14 -0
  87. pz_core/authoring/templates/app/package_init.py +8 -0
  88. pz_core/authoring/templates/app/pages_base.py +161 -0
  89. pz_core/authoring/templates/app/pages_readme.py +25 -0
  90. pz_core/authoring/templates/app/public.py +31 -0
  91. pz_core/authoring/templates/app/pyproject.py +77 -0
  92. pz_core/authoring/templates/app/readme.py +74 -0
  93. pz_core/authoring/templates/app/settings.py +46 -0
  94. pz_core/authoring/templates/app/static_app_js.py +24 -0
  95. pz_core/authoring/templates/app/static_readme.py +31 -0
  96. pz_core/authoring/templates/app/template_config_page.py +23 -0
  97. pz_core/authoring/templates/app/template_index_html.py +28 -0
  98. pz_core/authoring/templates/app/templates_readme.py +32 -0
  99. pz_core/authoring/templates/app/urls.py +36 -0
  100. pz_core/authoring/templates/app/views.py +36 -0
  101. pz_core/authoring/templates/project/__init__.py +1 -0
  102. pz_core/authoring/templates/project/agents.py +51 -0
  103. pz_core/authoring/templates/project/apps_container_readme.py +37 -0
  104. pz_core/authoring/templates/project/main_py.py +59 -0
  105. pz_core/authoring/templates/project/project_env.py +19 -0
  106. pz_core/authoring/templates/project/pyproject.py +26 -0
  107. pz_core/authoring/templates/project/pz_env_env.py +65 -0
  108. pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
  109. pz_core/authoring/templates/project/pz_jsonc.py +12 -0
  110. pz_core/authoring/templates/project/readme.py +94 -0
  111. pz_core/authoring/templates/project/root_gitkeep.py +8 -0
  112. pz_core/authoring/templates/shared/__init__.py +5 -0
  113. pz_core/authoring/templates/shared/text.py +10 -0
  114. pz_core/authoring/venv_service.py +87 -0
  115. pz_core/authoring/workspace.py +167 -0
  116. pz_core/cli.py +291 -0
  117. pz_core/cli_options.py +74 -0
  118. pz_core/core/__init__.py +3 -0
  119. pz_core/core/errors/__init__.py +5 -0
  120. pz_core/core/errors/models.py +117 -0
  121. pz_core/core/events/__init__.py +5 -0
  122. pz_core/core/events/registry.py +54 -0
  123. pz_core/core/extensions/__init__.py +51 -0
  124. pz_core/core/extensions/registry.py +790 -0
  125. pz_core/core/health/__init__.py +6 -0
  126. pz_core/core/health/contracts.py +10 -0
  127. pz_core/core/middlewares/__init__.py +6 -0
  128. pz_core/core/middlewares/models.py +24 -0
  129. pz_core/core/routing/__init__.py +5 -0
  130. pz_core/core/routing/models.py +21 -0
  131. pz_core/core/settings_contracts.py +25 -0
  132. pz_core/docs/README.md +20 -0
  133. pz_core/docs/distribution-README.md +438 -0
  134. pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
  135. 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
  136. 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
  137. 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
  138. 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
  139. 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
  140. 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
  141. 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
  142. 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
  143. 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
  144. 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
  145. 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
  146. 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
  147. 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
  148. 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
  149. 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
  150. 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
  151. 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
  152. 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
  153. 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
  154. 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
  155. 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
  156. 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
  157. 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
  158. 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
  159. 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
  160. 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
  161. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
  162. 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
  163. 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
  164. 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
  165. 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
  166. 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
  167. 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
  168. 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
  169. 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
  170. 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
  171. 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
  172. 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
  173. pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
  174. pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
  175. pz_core/infra/__init__.py +17 -0
  176. pz_core/infra/db/__init__.py +23 -0
  177. pz_core/infra/db/contracts.py +73 -0
  178. pz_core/infra/health/__init__.py +5 -0
  179. pz_core/infra/health/contracts.py +8 -0
  180. pz_core/infra/kv/__init__.py +5 -0
  181. pz_core/infra/kv/contracts.py +17 -0
  182. pz_core/infra/observability/__init__.py +23 -0
  183. pz_core/infra/observability/contracts.py +142 -0
  184. pz_core/infra/resilience/__init__.py +5 -0
  185. pz_core/infra/resilience/contracts.py +17 -0
  186. pz_core/infra/resources/__init__.py +5 -0
  187. pz_core/infra/resources/contracts.py +16 -0
  188. pz_core/infra/settings/__init__.py +17 -0
  189. pz_core/infra/settings/models.py +81 -0
  190. pz_core/infra/storage/__init__.py +5 -0
  191. pz_core/infra/storage/ports.py +27 -0
  192. pz_core/project_root_commands.py +282 -0
  193. pz_core/project_runtime_cli.py +344 -0
  194. pz_core/project_sources.py +253 -0
  195. pz_core/pz_launcher.py +209 -0
  196. pz_core/root_cli.py +70 -0
  197. pz_core/runtime/__init__.py +229 -0
  198. pz_core/runtime/access.py +86 -0
  199. pz_core/runtime/adapters/__init__.py +5 -0
  200. pz_core/runtime/adapters/base.py +18 -0
  201. pz_core/runtime/asyncio_bridge.py +18 -0
  202. pz_core/runtime/bindings/__init__.py +5 -0
  203. pz_core/runtime/bindings/container.py +50 -0
  204. pz_core/runtime/cli/__init__.py +5 -0
  205. pz_core/runtime/cli/_args.py +67 -0
  206. pz_core/runtime/cli/app_commands.py +417 -0
  207. pz_core/runtime/cli/check.py +214 -0
  208. pz_core/runtime/cli/db.py +297 -0
  209. pz_core/runtime/cli/main.py +89 -0
  210. pz_core/runtime/cli/resources.py +280 -0
  211. pz_core/runtime/discovery.py +23 -0
  212. pz_core/runtime/environment_integrity.py +157 -0
  213. pz_core/runtime/errors.py +5 -0
  214. pz_core/runtime/events.py +87 -0
  215. pz_core/runtime/facades/__init__.py +38 -0
  216. pz_core/runtime/facades/_capabilities.py +46 -0
  217. pz_core/runtime/facades/cache.py +103 -0
  218. pz_core/runtime/facades/database.py +71 -0
  219. pz_core/runtime/facades/events.py +380 -0
  220. pz_core/runtime/facades/health.py +101 -0
  221. pz_core/runtime/facades/mail.py +121 -0
  222. pz_core/runtime/facades/observability.py +102 -0
  223. pz_core/runtime/facades/providers.py +75 -0
  224. pz_core/runtime/facades/resources.py +52 -0
  225. pz_core/runtime/facades/storage.py +296 -0
  226. pz_core/runtime/health/__init__.py +5 -0
  227. pz_core/runtime/health/service.py +102 -0
  228. pz_core/runtime/host.py +188 -0
  229. pz_core/runtime/host_runner.py +282 -0
  230. pz_core/runtime/http/__init__.py +20 -0
  231. pz_core/runtime/http/app.py +576 -0
  232. pz_core/runtime/http_timing.py +173 -0
  233. pz_core/runtime/invocation.py +29 -0
  234. pz_core/runtime/json_safe.py +47 -0
  235. pz_core/runtime/lifecycle/__init__.py +25 -0
  236. pz_core/runtime/lifecycle/manager.py +533 -0
  237. pz_core/runtime/plan.py +214 -0
  238. pz_core/runtime/plan_context.py +33 -0
  239. pz_core/runtime/plan_snapshot.py +177 -0
  240. pz_core/runtime/registries/__init__.py +27 -0
  241. pz_core/runtime/registries/capabilities.py +101 -0
  242. pz_core/runtime/registries/providers.py +396 -0
  243. pz_core/runtime/resource_assets.py +344 -0
  244. pz_core/runtime/run_cli.py +211 -0
  245. pz_core/runtime/settings.py +888 -0
  246. pz_core/runtime/worker/__init__.py +21 -0
  247. pz_core/runtime/worker/engine.py +921 -0
  248. pz_core/runtime/worker/runtime.py +25 -0
  249. pz_core/testing/__init__.py +15 -0
  250. pz_core/testing/doc_route_contracts.py +305 -0
  251. pz_core/utils/__init__.py +44 -0
  252. pz_core/utils/env.py +65 -0
  253. pz_core/utils/project_jsonc/__init__.py +29 -0
  254. pz_core/utils/project_jsonc/document.py +420 -0
  255. pz_core/utils/project_settings.py +99 -0
  256. pz_foundation/__init__.py +50 -0
  257. pz_foundation/_contracts.py +81 -0
  258. pz_foundation/_errors.py +34 -0
  259. pz_foundation/api.py +14 -0
  260. pz_foundation/apps.py +127 -0
  261. pz_foundation/auth/__init__.py +1 -0
  262. pz_foundation/cache_control.py +233 -0
  263. pz_foundation/cli/__init__.py +2 -0
  264. pz_foundation/cli/workers.py +565 -0
  265. pz_foundation/configs/__init__.py +0 -0
  266. pz_foundation/configs/default.env +15 -0
  267. pz_foundation/configs/default.jsonc +452 -0
  268. pz_foundation/db/__init__.py +94 -0
  269. pz_foundation/db/aerich_executor.py +664 -0
  270. pz_foundation/db/config.py +358 -0
  271. pz_foundation/db/connection_manager.py +689 -0
  272. pz_foundation/db/connection_probe.py +204 -0
  273. pz_foundation/db/database.py +1291 -0
  274. pz_foundation/db/deps.py +47 -0
  275. pz_foundation/db/lifecycle_status.py +85 -0
  276. pz_foundation/db/migrations.py +477 -0
  277. pz_foundation/db/mysql.py +57 -0
  278. pz_foundation/db/postgresql.py +409 -0
  279. pz_foundation/db/production_pool_fallback.py +143 -0
  280. pz_foundation/db/public.py +45 -0
  281. pz_foundation/db/session.py +369 -0
  282. pz_foundation/db/sqlite.py +15 -0
  283. pz_foundation/db/tortoise_manager.py +724 -0
  284. pz_foundation/db/tortoise_psycopg.py +148 -0
  285. pz_foundation/docs/README.md +18 -0
  286. pz_foundation/docs/distribution-README.md +319 -0
  287. 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
  288. 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
  289. pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
  290. 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
  291. pz_foundation/health.py +105 -0
  292. pz_foundation/host/__init__.py +11 -0
  293. pz_foundation/host/builder.py +34 -0
  294. pz_foundation/host/cache_runtime.py +44 -0
  295. pz_foundation/host/db/__init__.py +17 -0
  296. pz_foundation/host/db/aerich_config.py +36 -0
  297. pz_foundation/host/db/config.py +106 -0
  298. pz_foundation/host/db/connection_manager.py +48 -0
  299. pz_foundation/host/db/deps.py +5 -0
  300. pz_foundation/host/db/orm_retry_patch.py +566 -0
  301. pz_foundation/host/db/request_adapter.py +325 -0
  302. pz_foundation/host/db/router.py +28 -0
  303. pz_foundation/host/db/session.py +284 -0
  304. pz_foundation/host/db/tortoise_manager.py +10 -0
  305. pz_foundation/host/idempotency.py +132 -0
  306. pz_foundation/host/lifespan.py +247 -0
  307. pz_foundation/host/redis_runtime.py +100 -0
  308. pz_foundation/host/web.py +790 -0
  309. pz_foundation/infra_provider.py +236 -0
  310. pz_foundation/kv/__init__.py +25 -0
  311. pz_foundation/kv/cache.py +1166 -0
  312. pz_foundation/kv/deps.py +84 -0
  313. pz_foundation/kv/public.py +25 -0
  314. pz_foundation/kv/redis_manager.py +1531 -0
  315. pz_foundation/lazy_exports.py +43 -0
  316. pz_foundation/lazy_imports.py +124 -0
  317. pz_foundation/lifecycle.py +392 -0
  318. pz_foundation/managed_workers.py +1117 -0
  319. pz_foundation/middlewares/__init__.py +26 -0
  320. pz_foundation/middlewares/_settings.py +250 -0
  321. pz_foundation/middlewares/analytics.py +124 -0
  322. pz_foundation/middlewares/cache_control.py +156 -0
  323. pz_foundation/middlewares/compression.py +202 -0
  324. pz_foundation/middlewares/cors.py +62 -0
  325. pz_foundation/middlewares/geo_country.py +44 -0
  326. pz_foundation/middlewares/inner_router.py +50 -0
  327. pz_foundation/middlewares/rate_limited/__init__.py +3 -0
  328. pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
  329. pz_foundation/middlewares/request_logging.py +104 -0
  330. pz_foundation/middlewares/route_owner.py +309 -0
  331. pz_foundation/middlewares/security_csrf.py +44 -0
  332. pz_foundation/middlewares/security_headers/__init__.py +4 -0
  333. pz_foundation/middlewares/security_headers/conflicts.py +44 -0
  334. pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
  335. pz_foundation/middlewares/security_headers/security_headers.py +44 -0
  336. pz_foundation/migrations/__init__.py +1 -0
  337. pz_foundation/migrations/pz_foundation/__init__.py +1 -0
  338. pz_foundation/models.py +22 -0
  339. pz_foundation/notifications/__init__.py +23 -0
  340. pz_foundation/notifications/email.py +542 -0
  341. pz_foundation/notifications/public.py +31 -0
  342. pz_foundation/observability/__init__.py +71 -0
  343. pz_foundation/observability/http.py +34 -0
  344. pz_foundation/observability/logger/__init__.py +49 -0
  345. pz_foundation/observability/logger/_bot_settings.py +126 -0
  346. pz_foundation/observability/logger/bot_message.py +592 -0
  347. pz_foundation/observability/logger/core.py +385 -0
  348. pz_foundation/observability/logger/delivery_audit.py +84 -0
  349. pz_foundation/observability/logger/feishu_bot.py +199 -0
  350. pz_foundation/observability/logger/telegram_bot.py +194 -0
  351. pz_foundation/observability/metrics.py +365 -0
  352. pz_foundation/observability/runtime.py +68 -0
  353. pz_foundation/public.py +405 -0
  354. pz_foundation/resources/__init__.py +12 -0
  355. pz_foundation/resources/builder.py +900 -0
  356. pz_foundation/resources/images.py +363 -0
  357. pz_foundation/root_cli.py +20 -0
  358. pz_foundation/routing/__init__.py +203 -0
  359. pz_foundation/routing/canonical.py +486 -0
  360. pz_foundation/routing/convertors.py +82 -0
  361. pz_foundation/routing/declarations.py +843 -0
  362. pz_foundation/routing/exports.py +148 -0
  363. pz_foundation/routing/loaders.py +138 -0
  364. pz_foundation/routing/manifest.py +215 -0
  365. pz_foundation/routing/manifest_provider.py +47 -0
  366. pz_foundation/routing/mounts.py +101 -0
  367. pz_foundation/routing/ordering.py +172 -0
  368. pz_foundation/routing/registry.py +133 -0
  369. pz_foundation/routing/utils.py +28 -0
  370. pz_foundation/runtime.py +234 -0
  371. pz_foundation/settings.py +253 -0
  372. pz_foundation/settings_normalization.py +130 -0
  373. pz_foundation/storage/__init__.py +25 -0
  374. pz_foundation/storage/local.py +209 -0
  375. pz_foundation/storage/public.py +106 -0
  376. pz_foundation/storage/s3.py +116 -0
  377. pz_foundation/storage/service.py +234 -0
  378. pz_foundation/urls.py +19 -0
  379. pz_foundation/utils/__init__.py +6 -0
  380. pz_foundation/utils/merge.py +160 -0
  381. pz_foundation/worker_replicas.py +55 -0
  382. pz_settings_center/__init__.py +5 -0
  383. pz_settings_center/api/__init__.py +5 -0
  384. pz_settings_center/api/runtime_overrides.py +360 -0
  385. pz_settings_center/apps.py +28 -0
  386. pz_settings_center/configs/__init__.py +0 -0
  387. pz_settings_center/configs/default.env +2 -0
  388. pz_settings_center/configs/default.jsonc +1 -0
  389. pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
  390. pz_settings_center/docs/README.md +12 -0
  391. pz_settings_center/docs/distribution-README.md +150 -0
  392. pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
  393. pz_settings_center/integration_payload.py +18 -0
  394. pz_settings_center/project_helpers.py +405 -0
  395. pz_settings_center/public.py +139 -0
  396. pz_settings_center/routing_helpers.py +73 -0
  397. pz_settings_center/runtime_override_provider.py +61 -0
  398. pz_settings_center/typed_settings.py +324 -0
  399. pz_settings_center/urls.py +9 -0
@@ -0,0 +1,558 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Sequence
4
+ from contextlib import contextmanager
5
+ from dataclasses import dataclass, replace
6
+ from importlib import invalidate_caches
7
+ import json
8
+ from pathlib import Path
9
+ import site
10
+ import subprocess
11
+ import sys
12
+ from typing import Any
13
+
14
+ from pz_core.runtime.errors import PzError, as_pz_error
15
+
16
+ from .app_init_service import (
17
+ AppInitSourcePlan,
18
+ AppInitSourcesResult,
19
+ SourcePackageInstallResult,
20
+ build_app_init_source_plan,
21
+ init_project_source_apps,
22
+ )
23
+ from .app_versions import (
24
+ declare_app_version,
25
+ query_app_versions,
26
+ reconcile_project_environment,
27
+ resolve_app_version,
28
+ )
29
+ from .dev_git import BaseBranch
30
+ from .dev_import import cache_git_source, import_cached_apps
31
+ from .dev_sources import (
32
+ DevTransactionResult,
33
+ InitDevSourcesRequest,
34
+ initialize_dev_sources,
35
+ )
36
+ from .project_settings_service import update_settings_file
37
+ from .ide_projection import sync_ide_projections
38
+ from .project_metadata_service import update_project_uv_sources
39
+ from .project_state import ensure_business_app_identity, ensure_project_state
40
+ from pz_core.project_sources import load_official_source_catalog
41
+ from .release import PublishResult, publish_app
42
+ from .scaffold_service import ensure_default_local_app, ensure_project_scaffold
43
+ from .sync_service import sync_project_targets
44
+ from .venv_service import (
45
+ ProjectVirtualenvResult,
46
+ ensure_project_virtualenv,
47
+ resolve_virtualenv_python,
48
+ )
49
+
50
+
51
+ ProgressReporter = Callable[[str], None]
52
+
53
+
54
+ @contextmanager
55
+ def _source_plan_import_paths(
56
+ plan: AppInitSourcePlan,
57
+ *,
58
+ project_venv: Path | None,
59
+ action: str,
60
+ ):
61
+ original = tuple(sys.path)
62
+ try:
63
+ if project_venv is not None:
64
+ for site_packages in _project_venv_site_packages(
65
+ project_venv,
66
+ action=action,
67
+ ):
68
+ site.addsitedir(str(site_packages))
69
+ if project_venv is None:
70
+ source_roots: list[str] = []
71
+ for package in plan.packages:
72
+ root = str(package.package_root)
73
+ if root not in source_roots:
74
+ source_roots.append(root)
75
+ for root in reversed(source_roots):
76
+ while root in sys.path:
77
+ sys.path.remove(root)
78
+ sys.path.insert(0, root)
79
+ invalidate_caches()
80
+ yield
81
+ finally:
82
+ sys.path[:] = original
83
+ invalidate_caches()
84
+
85
+
86
+ def _project_venv_site_packages(
87
+ project_venv: Path,
88
+ *,
89
+ action: str,
90
+ ) -> tuple[Path, ...]:
91
+ python = resolve_virtualenv_python(project_venv, action=action)
92
+ completed = subprocess.run(
93
+ (
94
+ str(python),
95
+ "-c",
96
+ "import json, site; print(json.dumps(site.getsitepackages()))",
97
+ ),
98
+ check=False,
99
+ capture_output=True,
100
+ text=True,
101
+ )
102
+ if completed.returncode != 0:
103
+ raise PzError(
104
+ code="PZ_APP_INIT_VENV_INSPECTION_FAILED",
105
+ message="failed to inspect project virtualenv import paths.",
106
+ stage="app_init",
107
+ owner="pz_core.authoring.orchestration_service",
108
+ action=action,
109
+ detail=(completed.stderr or completed.stdout or "site inspection failed").strip(),
110
+ )
111
+ try:
112
+ payload = json.loads(completed.stdout)
113
+ except json.JSONDecodeError as exc:
114
+ raise PzError(
115
+ code="PZ_APP_INIT_VENV_INSPECTION_FAILED",
116
+ message="project virtualenv returned invalid import path metadata.",
117
+ stage="app_init",
118
+ owner="pz_core.authoring.orchestration_service",
119
+ action=action,
120
+ detail=str(exc),
121
+ ) from exc
122
+ if not isinstance(payload, list) or not all(
123
+ isinstance(item, str) and item.strip() for item in payload
124
+ ):
125
+ raise PzError(
126
+ code="PZ_APP_INIT_VENV_INSPECTION_FAILED",
127
+ message="project virtualenv returned invalid import path metadata.",
128
+ stage="app_init",
129
+ owner="pz_core.authoring.orchestration_service",
130
+ action=action,
131
+ )
132
+ return tuple(Path(item).resolve() for item in payload)
133
+
134
+
135
+ @dataclass(frozen=True, slots=True)
136
+ class DevInitPreparationResult:
137
+ business_app_id: str
138
+ scaffold_created: bool
139
+ default_app_id: str | None
140
+ default_app_created: bool
141
+ project_venv: ProjectVirtualenvResult | None
142
+
143
+
144
+ @dataclass(frozen=True, slots=True)
145
+ class EnvInstallExecutionResult:
146
+ project_venv: ProjectVirtualenvResult
147
+ synced_targets: tuple[Any, ...]
148
+
149
+
150
+ @dataclass(frozen=True, slots=True)
151
+ class EnvInitExecutionResult:
152
+ initialized_project: bool
153
+ project_venv: ProjectVirtualenvResult | None
154
+ synced_targets: tuple[Any, ...]
155
+ settings_path: Path
156
+
157
+
158
+ @dataclass(frozen=True, slots=True)
159
+ class EnvSyncExecutionResult:
160
+ synced_targets: tuple[Any, ...]
161
+
162
+
163
+ @dataclass(frozen=True, slots=True)
164
+ class AppInitExecutionResult:
165
+ source_apps: AppInitSourcesResult
166
+ project_venv: ProjectVirtualenvResult | None
167
+ source_install: SourcePackageInstallResult
168
+ synced_targets: tuple[Any, ...]
169
+ settings_path: Path | None = None
170
+
171
+
172
+ @dataclass(frozen=True, slots=True)
173
+ class PublishBatchExecutionResult:
174
+ results: tuple[PublishResult, ...]
175
+ summary_message: str
176
+
177
+
178
+ def prepare_dev_init_project(
179
+ project_dir: Path,
180
+ *,
181
+ app_name: str | None,
182
+ action: str,
183
+ ) -> DevInitPreparationResult:
184
+ identity = ensure_business_app_identity(
185
+ project_dir,
186
+ app_name=app_name,
187
+ action=action,
188
+ )
189
+ scaffold_result = ensure_project_scaffold(project_dir)
190
+ ensure_project_state(project_dir, action=action)
191
+ default_app_result = ensure_default_local_app(
192
+ project_dir,
193
+ app_name=identity.business_app_id,
194
+ scaffold_created=scaffold_result.created,
195
+ action=action,
196
+ )
197
+ return DevInitPreparationResult(
198
+ business_app_id=identity.business_app_id,
199
+ scaffold_created=scaffold_result.created,
200
+ default_app_id=default_app_result.app_id,
201
+ default_app_created=default_app_result.created,
202
+ project_venv=None,
203
+ )
204
+
205
+
206
+ def execute_env_install(
207
+ project_dir: Path,
208
+ *,
209
+ action: str,
210
+ groups: Sequence[str] = (),
211
+ extras: Sequence[str] = (),
212
+ reinstall_packages: Sequence[str] = (),
213
+ project_only: bool = False,
214
+ existing_project_venv: ProjectVirtualenvResult | None = None,
215
+ sync_targets: Callable[..., tuple[Any, ...]] | None = None,
216
+ ) -> EnvInstallExecutionResult:
217
+ project_venv = existing_project_venv or ensure_project_virtualenv(
218
+ project_dir, action=action
219
+ )
220
+ synced_targets = (
221
+ sync_targets
222
+ if sync_targets is not None
223
+ else lambda path, **kwargs: sync_project_targets(path, action=action, **kwargs)
224
+ )(
225
+ project_dir,
226
+ groups=tuple(groups),
227
+ extras=tuple(extras),
228
+ reinstall_packages=tuple(reinstall_packages),
229
+ project_only=project_only,
230
+ )
231
+ return EnvInstallExecutionResult(
232
+ project_venv=project_venv,
233
+ synced_targets=synced_targets,
234
+ )
235
+
236
+
237
+ def execute_dev_init(
238
+ project_dir: Path,
239
+ *,
240
+ app_name: str | None,
241
+ base_branch: BaseBranch,
242
+ clone_sources: bool,
243
+ link: bool = False,
244
+ source_dir: str | None = None,
245
+ no_sync: bool,
246
+ action: str,
247
+ progress_reporter: ProgressReporter | None = None,
248
+ ) -> tuple[DevInitPreparationResult, DevTransactionResult]:
249
+ if progress_reporter is not None:
250
+ progress_reporter(f"Preparing project scaffold in {project_dir}.")
251
+ preparation = prepare_dev_init_project(
252
+ project_dir, app_name=app_name, action=action
253
+ )
254
+ if progress_reporter is not None:
255
+ if preparation.scaffold_created:
256
+ progress_reporter("Project scaffold is ready.")
257
+ if preparation.default_app_created and preparation.default_app_id is not None:
258
+ progress_reporter(
259
+ f"Default local app `{preparation.default_app_id}` is ready."
260
+ )
261
+ if link and clone_sources == (source_dir is not None):
262
+ raise PzError(
263
+ code="PZ_DEV_INIT_SOURCE_SELECTOR_INVALID",
264
+ message="pz dev init --link 必须且只能指定 --clone-sources 或 --source-dir。",
265
+ stage="dev",
266
+ owner="pz_core.authoring.orchestration_service",
267
+ action=action,
268
+ )
269
+ if not link and (clone_sources or source_dir is not None):
270
+ raise PzError(
271
+ code="PZ_DEV_INIT_SOURCE_SELECTOR_INVALID",
272
+ message="--clone-sources 和 --source-dir 只能与 --link 一起使用。",
273
+ stage="dev",
274
+ owner="pz_core.authoring.orchestration_service",
275
+ action=action,
276
+ )
277
+ if link:
278
+ if progress_reporter is not None:
279
+ progress_reporter("Binding the official pz bootstrap repository.")
280
+ shared_entry: Path | None = None
281
+ shared_entry_created = False
282
+ if source_dir is not None:
283
+ external = Path(source_dir).expanduser().resolve(strict=True)
284
+ if not external.is_dir() or not (external / ".git").exists():
285
+ raise PzError(
286
+ code="PZ_DEV_INIT_SOURCE_DIR_INVALID",
287
+ message="--source-dir 必须指向本地 pz Git checkout。",
288
+ stage="dev",
289
+ owner="pz_core.authoring.orchestration_service",
290
+ action=action,
291
+ )
292
+ shared_entry = project_dir / "apps" / ".sources" / "pz"
293
+ shared_entry.parent.mkdir(parents=True, exist_ok=True)
294
+ if shared_entry.is_symlink():
295
+ if shared_entry.resolve(strict=True) != external:
296
+ raise PzError(
297
+ code="PZ_DEV_SOURCE_CONFLICT",
298
+ message="apps/.sources/pz 已指向另一个共享 checkout。",
299
+ stage="dev",
300
+ owner="pz_core.authoring.orchestration_service",
301
+ action=action,
302
+ )
303
+ elif shared_entry.exists():
304
+ raise PzError(
305
+ code="PZ_DEV_SOURCE_CONFLICT",
306
+ message="apps/.sources/pz 已被现有路径占用。",
307
+ stage="dev",
308
+ owner="pz_core.authoring.orchestration_service",
309
+ action=action,
310
+ )
311
+ else:
312
+ shared_entry.symlink_to(external, target_is_directory=True)
313
+ shared_entry_created = True
314
+ try:
315
+ dev_sources = initialize_dev_sources(
316
+ InitDevSourcesRequest(
317
+ project_dir=project_dir,
318
+ app_name=preparation.business_app_id,
319
+ locators=("pz", "pz_settings_center", "pz_foundation"),
320
+ base_branch=base_branch,
321
+ )
322
+ )
323
+ except Exception:
324
+ if shared_entry_created and shared_entry is not None:
325
+ shared_entry.unlink(missing_ok=True)
326
+ raise
327
+ metadata = update_project_uv_sources(project_dir, action=action)
328
+ init_project_source_apps(project_dir, action=action, plan=metadata.plan)
329
+ else:
330
+ if progress_reporter is not None:
331
+ progress_reporter("Caching and importing official pz_apps source.")
332
+ root = load_official_source_catalog()["pz_apps"]
333
+ cache = cache_git_source(
334
+ repo_key=root.repo_key,
335
+ source=root.source,
336
+ branch="develop",
337
+ action=action,
338
+ )
339
+ app_specs = tuple(
340
+ (child.expected_app_id, child.subpath)
341
+ for child in root.children.values()
342
+ if child.kind == "app" and child.expected_app_id is not None
343
+ )
344
+ imported = import_cached_apps(
345
+ cache,
346
+ project_dir=project_dir,
347
+ apps=app_specs,
348
+ action=action,
349
+ )
350
+ dev_sources = DevTransactionResult(
351
+ operation="init",
352
+ project_dir=project_dir,
353
+ business_branch=preparation.business_app_id,
354
+ base_branch=base_branch,
355
+ repo_keys=(),
356
+ checkouts=(),
357
+ bindings=tuple(item.app_id for item in imported),
358
+ links=tuple(item.destination for item in imported),
359
+ )
360
+ settings_result = update_settings_file(project_dir)
361
+ if not no_sync:
362
+ if progress_reporter is not None:
363
+ progress_reporter("Running initial environment install.")
364
+ install_result = execute_env_install(
365
+ project_dir,
366
+ action=action,
367
+ existing_project_venv=preparation.project_venv,
368
+ )
369
+ preparation = replace(preparation, project_venv=install_result.project_venv)
370
+ if progress_reporter is not None:
371
+ progress_reporter(
372
+ f"Initial environment install finished for {len(install_result.synced_targets)} target(s)."
373
+ )
374
+ if progress_reporter is not None:
375
+ progress_reporter(f"Managed settings are ready at {settings_result.path}.")
376
+ sync_ide_projections(project_dir)
377
+ return preparation, dev_sources
378
+
379
+
380
+ def execute_env_init(
381
+ project_dir: Path,
382
+ *,
383
+ action: str,
384
+ no_sync: bool,
385
+ ) -> EnvInitExecutionResult:
386
+ scaffold_result = ensure_project_scaffold(project_dir)
387
+ settings_result = update_settings_file(project_dir)
388
+ install_result: EnvInstallExecutionResult | None = None
389
+ if not no_sync:
390
+ install_result = execute_env_install(project_dir, action=action)
391
+ return EnvInitExecutionResult(
392
+ initialized_project=scaffold_result.created,
393
+ project_venv=None if install_result is None else install_result.project_venv,
394
+ synced_targets=() if install_result is None else install_result.synced_targets,
395
+ settings_path=settings_result.path,
396
+ )
397
+
398
+
399
+ def execute_env_sync(
400
+ project_dir: Path,
401
+ *,
402
+ groups: Sequence[str],
403
+ extras: Sequence[str],
404
+ reinstall_packages: Sequence[str],
405
+ project_only: bool,
406
+ sync_targets: Callable[..., tuple[Any, ...]],
407
+ ) -> EnvSyncExecutionResult:
408
+ synced_targets = sync_targets(
409
+ project_dir,
410
+ groups=tuple(groups),
411
+ extras=tuple(extras),
412
+ reinstall_packages=tuple(reinstall_packages),
413
+ project_only=project_only,
414
+ )
415
+ return EnvSyncExecutionResult(synced_targets=synced_targets)
416
+
417
+
418
+ def execute_app_init(
419
+ project_dir: Path,
420
+ *,
421
+ no_sync: bool,
422
+ action: str,
423
+ ) -> AppInitExecutionResult:
424
+ ensure_project_scaffold(project_dir)
425
+ ensure_project_state(project_dir, action=action)
426
+ plan = build_app_init_source_plan(project_dir, action=action)
427
+ exact_versions: dict[str, str] = {}
428
+ for package in plan.app_packages:
429
+ state = query_app_versions(
430
+ package.app_id,
431
+ project_dir=project_dir,
432
+ action=action,
433
+ )
434
+ exact_versions[package.app_id] = resolve_app_version(
435
+ state,
436
+ None,
437
+ project_dir=project_dir,
438
+ action=action,
439
+ )
440
+ source_apps = init_project_source_apps(
441
+ project_dir,
442
+ action=action,
443
+ plan=plan,
444
+ )
445
+ for package in plan.app_packages:
446
+ declare_app_version(
447
+ package.app_id,
448
+ exact_versions[package.app_id],
449
+ project_dir=project_dir,
450
+ action=action,
451
+ )
452
+ project_venv: ProjectVirtualenvResult | None = None
453
+ source_install = SourcePackageInstallResult(
454
+ distributions=(),
455
+ install_target=None,
456
+ install_targets=(),
457
+ python=None,
458
+ command=(),
459
+ )
460
+ synced_targets: tuple[Any, ...] = ()
461
+ if not no_sync:
462
+ project_venv = ensure_project_virtualenv(project_dir, action=action)
463
+ if plan.app_packages:
464
+ first = plan.app_packages[0]
465
+ reconcile_project_environment(
466
+ first.app_id,
467
+ project_dir=project_dir,
468
+ action=action,
469
+ )
470
+ for package in plan.app_packages:
471
+ expected = exact_versions[package.app_id]
472
+ state = query_app_versions(
473
+ package.app_id,
474
+ project_dir=project_dir,
475
+ action=action,
476
+ )
477
+ if state.locked != expected or state.installed != expected:
478
+ raise PzError(
479
+ code="PZ_APP_VERSION_STATE_MISMATCH",
480
+ message=f"{package.distribution} did not converge to {expected}.",
481
+ stage="app_init",
482
+ owner="pz_core.authoring.orchestration_service",
483
+ action=action,
484
+ detail=f"locked={state.locked!r}; installed={state.installed!r}",
485
+ )
486
+ source_install = SourcePackageInstallResult(
487
+ distributions=tuple(
488
+ f"{package.distribution}=={exact_versions[package.app_id]}"
489
+ for package in plan.app_packages
490
+ ),
491
+ install_target=None,
492
+ install_targets=(),
493
+ python=resolve_virtualenv_python(project_venv.path, action=action),
494
+ command=("uv", "sync", "--active"),
495
+ )
496
+ with _source_plan_import_paths(
497
+ plan,
498
+ project_venv=None if project_venv is None else project_venv.path,
499
+ action=action,
500
+ ):
501
+ settings_path = update_settings_file(project_dir).path
502
+ return AppInitExecutionResult(
503
+ source_apps=source_apps,
504
+ project_venv=project_venv,
505
+ source_install=source_install,
506
+ synced_targets=synced_targets,
507
+ settings_path=settings_path,
508
+ )
509
+
510
+
511
+ def execute_publish_batch(
512
+ app_ids: Sequence[str],
513
+ *,
514
+ project_dir: Path,
515
+ target_name: str | None,
516
+ dry_run: bool,
517
+ action: str,
518
+ ) -> PublishBatchExecutionResult:
519
+ results: list[PublishResult] = []
520
+ for raw_app_id in app_ids:
521
+ try:
522
+ result = publish_app(
523
+ raw_app_id,
524
+ project_dir=project_dir,
525
+ target_name=target_name,
526
+ dry_run=dry_run,
527
+ action=action,
528
+ )
529
+ except Exception as exc:
530
+ if not results:
531
+ raise
532
+ root_error = as_pz_error(
533
+ exc, owner="pz_core.authoring", action=action, stage="cli"
534
+ )
535
+ completed = ", ".join(result.app_id for result in results)
536
+ raise PzError(
537
+ code="PZ_SCAFFOLD_PUBLISH_BATCH_FAILED",
538
+ message=(
539
+ f"batch publish stopped at `{raw_app_id}` after "
540
+ f"{len(results)} successful publish(es)."
541
+ ),
542
+ stage="cli",
543
+ owner="pz_core.authoring",
544
+ action=action,
545
+ detail=(
546
+ f"completed: {completed}; "
547
+ f"failed: {root_error.code}: {root_error.message}"
548
+ ),
549
+ ) from exc
550
+ results.append(result)
551
+ summary_message = (
552
+ f"Completed batch publish for {len(results)} package(s) using target "
553
+ f"{results[0].target.name if results else (target_name or 'default')}: "
554
+ f"{', '.join(result.app_id for result in results)}."
555
+ )
556
+ return PublishBatchExecutionResult(
557
+ results=tuple(results), summary_message=summary_message
558
+ )
@@ -0,0 +1,53 @@
1
+ {
2
+ "installed_apps": [],
3
+ "commands": {
4
+ // npm-like project root command extension point.
5
+ // string -> shell command
6
+ // array -> argv execution
7
+ // object -> {"command": "..."} or {"argv": ["..."], "description": "..."}
8
+ },
9
+ "project": {
10
+ "name": "PZ Project",
11
+ "default_module": "base",
12
+ "site_theme": "default",
13
+ // Single service base URL. Local/IP URLs may be adjusted by explicit
14
+ // APP_HOST or APP_PORT runtime overrides; domain URLs stay canonical.
15
+ "base_url": "http://127.0.0.1:8000",
16
+ "app_host": "0.0.0.0",
17
+ "api_v1_str": "/api/v1",
18
+ "static_version": 1,
19
+ "settings_backup_keep_count": 15,
20
+ "app_port": 8000,
21
+ "app_workers": 1,
22
+ "app_reload": false,
23
+ "static_target_path": "",
24
+ "static_target_owner": "",
25
+ "asset_dir": ".assets"
26
+ },
27
+ "resources": {
28
+ // Formal resource items that pz will discover inside each app package
29
+ // and merge in installed_apps order during startup compilation.
30
+ "items": [
31
+ { "name": "templates" },
32
+ { "name": "static" },
33
+ { "name": "locales" },
34
+ { "name": "pages" },
35
+ { "name": "template_config" },
36
+ { "name": "migrations" }
37
+ ],
38
+ // Root directory under cache_dir that stores merged resource artifacts.
39
+ "output_root": "resources",
40
+ // Manifest file name written under output_root.
41
+ "manifest_name": "manifest.json",
42
+ // Temporary staging directory name under output_root used before atomic swap/publish.
43
+ "staging_dir": "staging",
44
+ // Lock file name written under runtime_dir/locks for resource compilation.
45
+ "lock_name": "resources.lock"
46
+ },
47
+ "routing": {},
48
+ "events": {
49
+ "declared": {}
50
+ },
51
+ "app_replacements": {},
52
+ "apps": {}
53
+ }
@@ -0,0 +1,88 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from pz_core.utils.project_jsonc import load_jsonc_file
7
+
8
+
9
+ PROJECT_DEFAULT_JSONC_NAME = "project_default.jsonc"
10
+ _MANAGED_ROOT_KEYS = frozenset({"installed_apps", "middlewares"})
11
+ _OMIT = object()
12
+
13
+
14
+ def project_default_jsonc_path() -> Path:
15
+ return Path(__file__).resolve().with_name(PROJECT_DEFAULT_JSONC_NAME)
16
+
17
+
18
+ def load_project_default_jsonc_payload() -> dict[str, Any]:
19
+ payload = load_jsonc_file(
20
+ project_default_jsonc_path(),
21
+ code="PZ_PROJECT_DEFAULTS_INVALID",
22
+ owner="pz_core.authoring",
23
+ action="load_project_defaults",
24
+ )
25
+ if not isinstance(payload, dict):
26
+ return {}
27
+ return dict(payload)
28
+
29
+
30
+ def build_project_scaffold_payload(*, installed_apps: list[str] | None = None) -> dict[str, Any]:
31
+ return {
32
+ "installed_apps": list(installed_apps or []),
33
+ "commands": {},
34
+ "project": {
35
+ "static_version": 1,
36
+ },
37
+ }
38
+
39
+
40
+ def compact_project_payload(payload: dict[str, Any]) -> dict[str, Any]:
41
+ defaults = load_project_default_jsonc_payload()
42
+ compacted = _compact_value(payload, defaults, at_root=True)
43
+ if not isinstance(compacted, dict):
44
+ return {}
45
+ return dict(compacted)
46
+
47
+
48
+ def _compact_value(value: Any, default: Any, *, at_root: bool = False) -> Any:
49
+ if at_root and isinstance(value, dict):
50
+ compacted_root: dict[str, Any] = {}
51
+ default_mapping = default if isinstance(default, dict) else {}
52
+ for key, item in value.items():
53
+ if key in _MANAGED_ROOT_KEYS:
54
+ compacted_root[key] = item
55
+ continue
56
+ compacted = _compact_value(item, default_mapping.get(key, _OMIT))
57
+ if compacted is _OMIT:
58
+ continue
59
+ compacted_root[key] = compacted
60
+ return compacted_root
61
+
62
+ if isinstance(value, dict):
63
+ default_mapping = default if isinstance(default, dict) else None
64
+ compacted_mapping: dict[str, Any] = {}
65
+ for key, item in value.items():
66
+ next_default = default_mapping.get(key, _OMIT) if isinstance(default_mapping, dict) else _OMIT
67
+ compacted = _compact_value(item, next_default)
68
+ if compacted is _OMIT:
69
+ continue
70
+ compacted_mapping[key] = compacted
71
+ if compacted_mapping:
72
+ return compacted_mapping
73
+ if isinstance(default_mapping, dict):
74
+ return _OMIT
75
+ return value
76
+
77
+ if default is not _OMIT and value == default:
78
+ return _OMIT
79
+ return value
80
+
81
+
82
+ __all__ = [
83
+ "PROJECT_DEFAULT_JSONC_NAME",
84
+ "build_project_scaffold_payload",
85
+ "compact_project_payload",
86
+ "load_project_default_jsonc_payload",
87
+ "project_default_jsonc_path",
88
+ ]