@tdk-landscape/tdk-cli-core 1.3.15 → 1.3.26

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 (274) hide show
  1. package/Tiltfile +144 -0
  2. package/discovery/AGENTS.md +362 -0
  3. package/discovery/TILT_DISCOVERY.star +424 -0
  4. package/discovery/Tiltfile +58 -0
  5. package/discovery/config.star +258 -0
  6. package/discovery/constants.star +127 -0
  7. package/discovery/deterministic.star +211 -0
  8. package/discovery/discovery_daemon.star +191 -0
  9. package/discovery/discovery_orchestrator.star +460 -0
  10. package/discovery/filtering.star +5 -0
  11. package/discovery/identity-management-backend/service.yaml +26 -0
  12. package/discovery/identity-management-frontend/service.yaml +29 -0
  13. package/discovery/identity-sdk/service.yaml +9 -0
  14. package/discovery/incremental_discovery.star +213 -0
  15. package/discovery/indexing.star +7 -0
  16. package/discovery/json_manifest_scanner.star +51 -0
  17. package/discovery/libraries.star +46 -0
  18. package/discovery/loading.star +23 -0
  19. package/discovery/manifest/constants.star +104 -0
  20. package/discovery/manifest/loading.star +386 -0
  21. package/discovery/manifest/normalize.star +281 -0
  22. package/discovery/manifest/validation.star +108 -0
  23. package/discovery/normalization.star +11 -0
  24. package/discovery/registry.star +544 -0
  25. package/discovery/resource_snapshot.py +382 -0
  26. package/discovery/resource_snapshot.star +143 -0
  27. package/discovery/schemas.star +1 -0
  28. package/discovery/services/platform/cdc/debezium/nats-connector/service.yaml +9 -0
  29. package/discovery/services/platform/cdc/nats-http-bridge/service.yaml +9 -0
  30. package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +26 -0
  31. package/discovery/services/platform/synthetic-monitor/service.yaml +9 -0
  32. package/discovery/test_resource_snapshot.py +251 -0
  33. package/discovery/validation.star +78 -0
  34. package/discovery/versioning.star +1 -0
  35. package/dist/commands/config.d.ts.map +1 -1
  36. package/dist/commands/config.js +11 -0
  37. package/dist/commands/config.js.map +1 -1
  38. package/dist/commands/doctor.d.ts.map +1 -1
  39. package/dist/commands/doctor.js +1 -2
  40. package/dist/commands/doctor.js.map +1 -1
  41. package/dist/commands/project.d.ts.map +1 -1
  42. package/dist/commands/project.js +36 -41
  43. package/dist/commands/project.js.map +1 -1
  44. package/dist/commands/resource.d.ts.map +1 -1
  45. package/dist/commands/resource.js +51 -55
  46. package/dist/commands/resource.js.map +1 -1
  47. package/dist/commands/stack.d.ts.map +1 -1
  48. package/dist/commands/stack.js +22 -24
  49. package/dist/commands/stack.js.map +1 -1
  50. package/dist/commands/ui.d.ts.map +1 -1
  51. package/dist/commands/ui.js +1 -2
  52. package/dist/commands/ui.js.map +1 -1
  53. package/dist/commands/up.d.ts.map +1 -1
  54. package/dist/commands/up.js +1 -2
  55. package/dist/commands/up.js.map +1 -1
  56. package/dist/commands/upgrade.d.ts +8 -0
  57. package/dist/commands/upgrade.d.ts.map +1 -1
  58. package/dist/commands/upgrade.js +59 -18
  59. package/dist/commands/upgrade.js.map +1 -1
  60. package/dist/generator/extension-fetch.d.ts +19 -0
  61. package/dist/generator/extension-fetch.d.ts.map +1 -1
  62. package/dist/generator/extension-fetch.js +71 -5
  63. package/dist/generator/extension-fetch.js.map +1 -1
  64. package/dist/generator/template-engine.d.ts +1 -0
  65. package/dist/generator/template-engine.d.ts.map +1 -1
  66. package/dist/generator/template-engine.js +50 -6
  67. package/dist/generator/template-engine.js.map +1 -1
  68. package/dist/utils/command-helpers.d.ts.map +1 -1
  69. package/dist/utils/command-helpers.js +7 -9
  70. package/dist/utils/command-helpers.js.map +1 -1
  71. package/dist/utils/constants.d.ts +1 -0
  72. package/dist/utils/constants.d.ts.map +1 -1
  73. package/dist/utils/constants.js +1 -0
  74. package/dist/utils/constants.js.map +1 -1
  75. package/dist/utils/errors.d.ts +2 -0
  76. package/dist/utils/errors.d.ts.map +1 -1
  77. package/dist/utils/errors.js +6 -1
  78. package/dist/utils/errors.js.map +1 -1
  79. package/dist/utils/project-features.d.ts.map +1 -1
  80. package/dist/utils/project-features.js +1 -1
  81. package/dist/utils/project-features.js.map +1 -1
  82. package/dist/utils/resource-features.d.ts.map +1 -1
  83. package/dist/utils/resource-features.js +2 -2
  84. package/dist/utils/resource-features.js.map +1 -1
  85. package/dist/utils/tar.js +4 -4
  86. package/dist/utils/tar.js.map +1 -1
  87. package/dist/utils/validation.d.ts +7 -0
  88. package/dist/utils/validation.d.ts.map +1 -1
  89. package/dist/utils/validation.js +9 -0
  90. package/dist/utils/validation.js.map +1 -1
  91. package/engine/AGENTS.md +705 -0
  92. package/engine/README.md +29 -0
  93. package/engine/REFACTORING_MANIFEST_SYSTEM.md +974 -0
  94. package/engine/Tiltfile +80 -0
  95. package/engine/assets/docker/golden-layers.Dockerfile +221 -0
  96. package/engine/assets/scripts/cleanup-completed-migrator-images.sh +37 -0
  97. package/engine/assets/scripts/cleanup-tilt-images.sh +120 -0
  98. package/engine/assets/scripts/mac-m1-resource-monitor.sh +121 -0
  99. package/engine/config.star +3 -0
  100. package/engine/docs/AUTODISCOVERY_TEST.md +182 -0
  101. package/engine/docs/C4-ARCHITECTURE-operations.md +396 -0
  102. package/engine/docs/C4-ARCHITECTURE-overview.md +284 -0
  103. package/engine/docs/C4-ARCHITECTURE.md +17 -0
  104. package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +349 -0
  105. package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +357 -0
  106. package/engine/docs/README.md +284 -0
  107. package/engine/entrypoint.star +97 -0
  108. package/engine/lifecycle/orchestrator.star +260 -0
  109. package/engine/paths.star +717 -0
  110. package/engine/schemas/manifest-schema.json +301 -0
  111. package/engine/schemas/service-schema.json +301 -0
  112. package/engine/scripts/README.md +89 -0
  113. package/engine/scripts/build-and-publish-lib.sh +205 -0
  114. package/engine/scripts/check-lib-publish.sh +85 -0
  115. package/engine/scripts/debug-container.sh +258 -0
  116. package/engine/scripts/generate-manifest.sh +197 -0
  117. package/engine/spec.master +702 -0
  118. package/engine/spec.master.example +341 -0
  119. package/engine/topologies/README.md +34 -0
  120. package/engine/topologies/platform/docker/AGENTS.md +59 -0
  121. package/engine/topologies/platform/docker/auth/auth.star +167 -0
  122. package/engine/topologies/platform/docker/build/golden_image.star +37 -0
  123. package/engine/topologies/platform/docker/build/golden_image_build.star +82 -0
  124. package/engine/topologies/platform/docker/build/golden_image_constants.star +93 -0
  125. package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +291 -0
  126. package/engine/topologies/platform/docker/compose/compose.star +636 -0
  127. package/engine/topologies/platform/docker/compose/compose_helpers.star +52 -0
  128. package/engine/topologies/platform/docker/compose/traefik_standalone.star +53 -0
  129. package/engine/topologies/platform/docker/config/bunignore.star +142 -0
  130. package/engine/topologies/platform/docker/config/dockerignore.star +150 -0
  131. package/engine/topologies/platform/docker/constants.star +170 -0
  132. package/engine/topologies/platform/docker/dockerfile/dockerfile.star +54 -0
  133. package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +73 -0
  134. package/engine/topologies/platform/docker/index.star +27 -0
  135. package/engine/topologies/platform/docker/layers/bun_helpers.star +23 -0
  136. package/engine/topologies/platform/docker/layers/infisical/index.star +40 -0
  137. package/engine/topologies/platform/docker/layers/infisical/infisical_docker.star +262 -0
  138. package/engine/topologies/platform/docker/layers/l1_base_layers.star +87 -0
  139. package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +125 -0
  140. package/engine/topologies/platform/docker/layers/l3_builder_layers.star +209 -0
  141. package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +214 -0
  142. package/engine/topologies/platform/docker/layers/prisma/constants.star +135 -0
  143. package/engine/topologies/platform/docker/layers/prisma/db_readiness.star +96 -0
  144. package/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +109 -0
  145. package/engine/topologies/platform/docker/layers/prisma/migrate_script.star +98 -0
  146. package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +126 -0
  147. package/engine/topologies/platform/docker/layers/prisma/prisma_runtime.star +161 -0
  148. package/engine/topologies/platform/docker/layers/prisma/secret_resolution.star +119 -0
  149. package/engine/topologies/platform/docker/networking/api_path_constants.star +230 -0
  150. package/engine/topologies/platform/docker/networking/sablier_container_cycle.star +27 -0
  151. package/engine/topologies/platform/docker/networking/traefik.star +232 -0
  152. package/engine/topologies/platform/docker/networking/traefik_constants.star +146 -0
  153. package/engine/topologies/platform/docker/networking/traefik_helpers.star +160 -0
  154. package/engine/topologies/platform/docker/secrets/infisical.star +135 -0
  155. package/engine/topologies/platform/net/proxy.star +4 -0
  156. package/engine/topologies/platform/registries/local.star +4 -0
  157. package/engine/topologies/platform/security/secrets.star +239 -0
  158. package/engine/topologies/platform/state/relational.star +4 -0
  159. package/engine/topologies/tilt/common/AGENTS.md +59 -0
  160. package/engine/topologies/tilt/common/utils.star +364 -0
  161. package/engine/topologies/tilt/common/utils_debug.star +69 -0
  162. package/engine/topologies/tilt/common/utils_deterministic.star +168 -0
  163. package/engine/topologies/tilt/common/utils_docker_networks.star +46 -0
  164. package/engine/topologies/tilt/common/utils_env.star +43 -0
  165. package/engine/topologies/tilt/common/utils_output.star +97 -0
  166. package/engine/topologies/tilt/config/AGENTS.md +68 -0
  167. package/engine/topologies/tilt/config/defaults.star +3 -0
  168. package/engine/topologies/tilt/config/feature_flags.star +10 -0
  169. package/engine/topologies/tilt/config/global.star +55 -0
  170. package/engine/topologies/tilt/config/profiles.star +382 -0
  171. package/engine/topologies/tilt/generators/agents_md.star +62 -0
  172. package/engine/topologies/tilt/generators/api_gateway.star +145 -0
  173. package/engine/topologies/tilt/generators/index.star +124 -0
  174. package/engine/topologies/tilt/generators/infisical/README.md +424 -0
  175. package/engine/topologies/tilt/generators/infisical/examples.star +312 -0
  176. package/engine/topologies/tilt/generators/infisical/index.star +57 -0
  177. package/engine/topologies/tilt/generators/infisical/machine_identity.star +420 -0
  178. package/engine/topologies/tilt/generators/infisical/organization.star +534 -0
  179. package/engine/topologies/tilt/generators/infisical/path_manager.star +476 -0
  180. package/engine/topologies/tilt/generators/infisical/secrets_generator.star +420 -0
  181. package/engine/topologies/tilt/generators/nginx_conf.star +143 -0
  182. package/engine/topologies/tilt/generators/npmrc.star +111 -0
  183. package/engine/topologies/tilt/generators/tsconfig.star +23 -0
  184. package/engine/topologies/tilt/generators/typescript/backend_library_tsconfig.star +71 -0
  185. package/engine/topologies/tilt/generators/typescript/backend_tsconfig.star +124 -0
  186. package/engine/topologies/tilt/generators/typescript/common.star +7 -0
  187. package/engine/topologies/tilt/generators/typescript/frontend_library_tsconfig.star +76 -0
  188. package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +110 -0
  189. package/engine/topologies/tilt/generators/typescript/include.star +23 -0
  190. package/engine/topologies/tilt/generators/typescript/playwright_config.star +40 -0
  191. package/engine/topologies/tilt/generators/typescript/prisma_config.star +49 -0
  192. package/engine/topologies/tilt/generators/validators.star +853 -0
  193. package/engine/topologies/tilt/generators/vite/backend.star +78 -0
  194. package/engine/topologies/tilt/generators/vite/frontend.star +98 -0
  195. package/engine/topologies/tilt/generators/vite/generators.star +43 -0
  196. package/engine/topologies/tilt/generators/vite/helpers.star +244 -0
  197. package/engine/topologies/tilt/generators/vite/library.star +65 -0
  198. package/engine/topologies/tilt/generators/vite/sdk.star +73 -0
  199. package/engine/topologies/tilt/generators/vite/templates.star +737 -0
  200. package/engine/topologies/tilt/generators/vite_config.star +22 -0
  201. package/engine/topologies/tilt/manifest/AGENTS.md +61 -0
  202. package/engine/topologies/tilt/manifest/README.md +693 -0
  203. package/engine/topologies/tilt/manifest/__init__.star +218 -0
  204. package/engine/topologies/tilt/manifest/constants.star +252 -0
  205. package/engine/topologies/tilt/manifest/errors.star +266 -0
  206. package/engine/topologies/tilt/manifest/integration.star +339 -0
  207. package/engine/topologies/tilt/manifest/json_to_yaml.py +54 -0
  208. package/engine/topologies/tilt/manifest/loader.star +214 -0
  209. package/engine/topologies/tilt/manifest/mapper.star +227 -0
  210. package/engine/topologies/tilt/manifest/parser.star +400 -0
  211. package/engine/topologies/tilt/manifest/schema.star +462 -0
  212. package/engine/topologies/tilt/manifest/tests/test_integration.star +276 -0
  213. package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +397 -0
  214. package/engine/topologies/tilt/manifest/tests/test_manifest.star +316 -0
  215. package/engine/topologies/tilt/manifest/tests/test_validator.star +470 -0
  216. package/engine/topologies/tilt/manifest/validator.star +717 -0
  217. package/engine/topologies/tilt/manifest/yaml_to_json.py +18 -0
  218. package/engine/topologies/tilt/resources/AGENTS.md +71 -0
  219. package/engine/topologies/tilt/resources/conditions.star +3 -0
  220. package/engine/topologies/tilt/resources/databases.star +244 -0
  221. package/engine/topologies/tilt/resources/declaration.star +3 -0
  222. package/engine/topologies/tilt/resources/deps.star +3 -0
  223. package/engine/topologies/tilt/resources/infra-loader.star +437 -0
  224. package/engine/topologies/tilt/resources/libs.star +30 -0
  225. package/engine/topologies/tilt/resources/libs_discovery.star +102 -0
  226. package/engine/topologies/tilt/resources/libs_paths.star +79 -0
  227. package/engine/topologies/tilt/resources/libs_resource_definition.star +151 -0
  228. package/engine/topologies/tilt/resources/libs_setup.star +164 -0
  229. package/engine/topologies/tilt/resources/libs_tsconfig.star +37 -0
  230. package/engine/topologies/tilt/resources/orchestrator/apply.star +77 -0
  231. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +431 -0
  232. package/engine/topologies/tilt/resources/orchestrator/apply_manifest_orchestration.star +81 -0
  233. package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +148 -0
  234. package/engine/topologies/tilt/resources/orchestrator/apply_resource_validation.star +36 -0
  235. package/engine/topologies/tilt/resources/orchestrator/apply_runtime_flags.star +44 -0
  236. package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +164 -0
  237. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/AGENTS.md +75 -0
  238. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/index.star +21 -0
  239. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +134 -0
  240. package/engine/topologies/tilt/resources/orchestrator/generators/env.star +258 -0
  241. package/engine/topologies/tilt/resources/orchestrator/generators/frontend.star +169 -0
  242. package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +524 -0
  243. package/engine/topologies/tilt/resources/orchestrator/helpers.star +33 -0
  244. package/engine/topologies/tilt/resources/orchestrator.star +54 -0
  245. package/engine/topologies/tilt/resources/ordering.star +3 -0
  246. package/engine/topologies/tilt/resources/triggers.star +3 -0
  247. package/engine/topologies/tilt/resources/watchers.star +299 -0
  248. package/engine/where-things-live.star +717 -0
  249. package/ext/Tiltfile +66 -0
  250. package/ext/ide-components/README.md +219 -0
  251. package/ext/ide-components/code_executor/server.py +268 -0
  252. package/ext/ide-components/code_viewer/server.py +206 -0
  253. package/ext/ide-components/config_inspector/server.py +1050 -0
  254. package/ext/ide-components/file_browser/server.py +285 -0
  255. package/ext/ide-components/shared/config_service.py +469 -0
  256. package/ext/ide-components/shared/file_utils.py +298 -0
  257. package/ext/ide-components/shared/http_utils.py +232 -0
  258. package/ext/ide-components/shared/static/styles.css +1334 -0
  259. package/ext/ide-components/shared/syntax_highlighter.py +140 -0
  260. package/ext/ide-components/shared/template_engine.py +123 -0
  261. package/ext/ide-components/shared/templates/base.html +121 -0
  262. package/ext/ide-components/shared/test_config_service.py +326 -0
  263. package/ext/ide-components/shared/tilt_integration.py +158 -0
  264. package/ext/ui-enhancements/cron-status-server.sh +49 -0
  265. package/ext/ui-enhancements/cron-status-tracker.sh +146 -0
  266. package/ext/ui-enhancements/extension.yaml +36 -0
  267. package/ext/ui-enhancements/tiltfile.py +99 -0
  268. package/ext/ui-enhancements/ui/cron-jobs-tab.css +396 -0
  269. package/ext/ui-enhancements/ui/help-panel.css +279 -0
  270. package/ext/ui-enhancements/ui/icons.css +125 -0
  271. package/ext/ui-enhancements/ui/tooltips.css +114 -0
  272. package/package.json +13 -9
  273. package/specs/specs/TILT_SERVICE_DEFAULTS.star +205 -0
  274. package/specs/specs/TILT_TECH_STACK.star +159 -0
@@ -0,0 +1,400 @@
1
+ # =============================================================================
2
+ # 📋 MANIFEST MODULE - PARSER
3
+ # =============================================================================
4
+ # Path: .tilt/topologies/tilt/manifest/parser.star
5
+ # Purpose: JSON parsing and manifest normalization
6
+ # Status: Phase 2 of manifest system refactoring
7
+ # =============================================================================
8
+
9
+ # === INLINED CONSTANTS for pure extension loading ===
10
+ ORM = "prisma"
11
+ DEFAULTS = {}
12
+
13
+ # === END INLINED CONSTANTS ===
14
+
15
+
16
+ load("./constants.star",
17
+ "MANIFEST_DEFAULTS",
18
+ "MANIFEST_FILENAME",
19
+ "VALID_APP_TYPES",
20
+ "DEFAULT_SYNCS",
21
+ "AUTOGENERATED_CONFIG_PATHS",
22
+ "TRAEFIK_DEFAULTS",
23
+ )
24
+ load("./schema.star", "ManifestSchema")
25
+ load("./errors.star", "ManifestErrors")
26
+
27
+
28
+ def parse(content, path=""):
29
+ """
30
+ Parse JSON content into manifest dict.
31
+
32
+ Args:
33
+ content: Raw JSON string
34
+ path: Optional path for error context
35
+
36
+ Returns:
37
+ struct(
38
+ manifest=None, # Parsed manifest dict or None
39
+ error=None, # Error message or None
40
+ warnings=[], # List of warning messages
41
+ )
42
+ """
43
+ warnings = []
44
+
45
+ if not content or not str(content).strip():
46
+ return struct(
47
+ manifest=None,
48
+ error="Empty content provided",
49
+ warnings=warnings,
50
+ )
51
+
52
+ # Parse JSON
53
+ manifest = decode_json(content)
54
+
55
+ if manifest == None:
56
+ error = ManifestErrors.new(
57
+ message="Failed to parse JSON" + (" in " + path if path else ""),
58
+ category=ManifestErrors.CATEGORY['PARSE'],
59
+ severity=ManifestErrors.SEVERITY['ERROR'],
60
+ context={'path': path} if path else {},
61
+ )
62
+ return struct(
63
+ manifest=None,
64
+ error=ManifestErrors.format(error),
65
+ warnings=warnings,
66
+ )
67
+
68
+ # Note: 'dependencies' field is no longer supported, use 'dependsOn'
69
+
70
+ return struct(
71
+ manifest=manifest,
72
+ error=None,
73
+ warnings=warnings,
74
+ )
75
+
76
+ def normalize(manifest, resource_path=""):
77
+ """
78
+ Normalize manifest with default values and computed fields.
79
+
80
+ Args:
81
+ manifest: Raw parsed manifest dict
82
+ resource_path: Resource directory path for context
83
+
84
+ Returns:
85
+ Normalized manifest dict with all fields populated
86
+ """
87
+ normalized = {}
88
+ warnings = []
89
+
90
+ # Copy all existing fields
91
+ for key, value in manifest.items():
92
+ normalized[key] = value
93
+
94
+ # 1. Apply defaults for missing fields
95
+ for field, default_value in MANIFEST_DEFAULTS.items():
96
+ if field not in normalized or normalized[field] == None:
97
+ normalized[field] = default_value
98
+
99
+ # 2. Compute derived fields
100
+
101
+ # Compute appType from path if missing
102
+ if not normalized.get('appType'):
103
+ normalized['appType'] = _determine_app_type(normalized, resource_path)
104
+
105
+ # Compute stack from path if missing
106
+ if not normalized.get('stack'):
107
+ extracted = extract_stack_from_path(resource_path)
108
+ normalized['stack'] = extracted
109
+
110
+ # Compute syncs if not provided
111
+ if normalized.get('syncs') == None or normalized.get('syncs') == []:
112
+ normalized['syncs'] = _compute_syncs(
113
+ normalized['appType'],
114
+ normalized.get('features', [])
115
+ )
116
+
117
+ # Compute backendName for frontends if missing
118
+ if normalized['appType'] == 'frontend' and not normalized.get('backendName'):
119
+ app_name = normalized.get('appName', '')
120
+ if app_name.endswith('-frontend'):
121
+ normalized['backendName'] = app_name.replace('-frontend', '-backend')
122
+
123
+ # Normalize environment variables
124
+ if not normalized.get('envVars'):
125
+ normalized['envVars'] = {}
126
+
127
+ # Normalize dependsOn
128
+ if 'dependencies' in manifest and not normalized.get('dependsOn'):
129
+ normalized['dependsOn'] = manifest['dependencies']
130
+ if not normalized.get('dependsOn'):
131
+ normalized['dependsOn'] = []
132
+
133
+ # 3. Set up Traefik configuration defaults
134
+ if not normalized.get('traefik'):
135
+ normalized['traefik'] = {}
136
+
137
+ # Ensure traefik has pathPrefix - REQUIRED field
138
+ if not normalized['traefik'].get('pathPrefix'):
139
+ app_name = normalized.get('appName', 'unknown')
140
+ resource_path = normalized.get('_resource_path', 'unknown')
141
+
142
+ # Fail loudly - pathPrefix is required
143
+ error_msg = """MANIFEST ERROR: Missing required 'traefik.pathPrefix' in {}
144
+
145
+ Resource: {}
146
+ File: service.json
147
+
148
+ To fix, add:
149
+ "traefik": {{
150
+ "pathPrefix": "/api/v1/YOUR-PATH"
151
+ }}
152
+
153
+ Example:
154
+ "traefik": {{
155
+ "pathPrefix": "/api/v1/order-management"
156
+ }}""".format(resource_path, app_name)
157
+ fail(error_msg)
158
+
159
+ # Add default priority if not set
160
+ if 'priority' not in normalized['traefik']:
161
+ normalized['traefik']['priority'] = TRAEFIK_DEFAULTS['priority']
162
+
163
+ # 4. Add internal metadata
164
+ normalized['_manifest'] = manifest # Original manifest
165
+ normalized['_resource_path'] = resource_path
166
+ normalized['_normalized'] = True
167
+
168
+ return normalized
169
+
170
+ def extract_resource_path(manifest_path):
171
+ """
172
+ Extract resource directory path from manifest file path.
173
+
174
+ Args:
175
+ manifest_path: Path to manifest JSON file
176
+
177
+ Returns:
178
+ Resource directory path
179
+ """
180
+ # Remove manifest filename
181
+ if manifest_path.endswith("/" + MANIFEST_FILENAME):
182
+ return manifest_path[:-len("/" + MANIFEST_FILENAME)]
183
+
184
+ # If it's just a filename, try to find the directory
185
+ parts = manifest_path.rsplit("/", 1)
186
+ if len(parts) == 2 and parts[1] == MANIFEST_FILENAME:
187
+ return parts[0]
188
+
189
+ return manifest_path
190
+
191
+ def extract_stack_from_path(resource_path):
192
+ """
193
+ Extract stack from resource path.
194
+
195
+ Args:
196
+ resource_path: Resource directory path
197
+
198
+ Returns:
199
+ Stack string from manifest (e.g., 'identity', 'booking')
200
+ """
201
+ parts = resource_path.split("/")
202
+
203
+ # Expected path: services/product/{stack}/{resource-name}
204
+ if len(parts) >= 4 and parts[0] == "services" and parts[1] == "product":
205
+ stack = parts[2]
206
+ # Handle special cases
207
+ if stack == "profile":
208
+ return "identity"
209
+ if stack == "order-planner":
210
+ return "order-planner"
211
+ return stack
212
+
213
+ # Fallback: try to extract from resource name
214
+ if len(parts) >= 1:
215
+ resource_name = parts[-1]
216
+ # Extract stack from resource name (e.g., {stack}-management-backend -> {stack})
217
+ name_parts = resource_name.split("-")
218
+ if len(name_parts) >= 1:
219
+ return name_parts[0]
220
+
221
+ return "unknown"
222
+
223
+ def _determine_app_type(manifest, resource_path):
224
+ """
225
+ Determine app type from manifest or resource path.
226
+
227
+ Args:
228
+ manifest: Manifest dict
229
+ resource_path: Resource directory path
230
+
231
+ Returns:
232
+ App type string ('frontend', 'backend', 'library', etc.)
233
+ """
234
+ # Check if manifest has explicit appType
235
+ if manifest.get("appType") and manifest["appType"] in VALID_APP_TYPES:
236
+ return manifest["appType"]
237
+
238
+ # Extract from path
239
+ dir_name = resource_path.split("/")[-1] if resource_path else ""
240
+
241
+ if dir_name.endswith("-frontend"):
242
+ return "frontend"
243
+ if dir_name.endswith("-backend"):
244
+ return "backend"
245
+ if dir_name.endswith("-migrator"):
246
+ return "migrator"
247
+ if dir_name.endswith("-sdk"):
248
+ return "sdk"
249
+
250
+ # Default to backend
251
+ return "backend"
252
+
253
+ def _compute_syncs(app_type, features):
254
+ """
255
+ Compute default sync paths based on app type and features.
256
+
257
+ Args:
258
+ app_type: App type string
259
+ features: List of feature strings
260
+
261
+ Returns:
262
+ List of sync paths
263
+ """
264
+ syncs = []
265
+
266
+ # Start with default syncs for app type
267
+ if app_type in DEFAULT_SYNCS:
268
+ syncs.extend(DEFAULT_SYNCS[app_type])
269
+
270
+ # Add feature-specific syncs
271
+ if ORM in features and app_type == "backend":
272
+ if ORM not in syncs:
273
+ syncs.append(ORM)
274
+
275
+ # Remove duplicates while preserving order
276
+ seen = {}
277
+ unique_syncs = []
278
+ for sync in syncs:
279
+ if sync not in seen:
280
+ seen[sync] = True
281
+ unique_syncs.append(sync)
282
+
283
+ return unique_syncs
284
+
285
+ def parse_traefik_config(manifest):
286
+ """
287
+ Parse and normalize Traefik configuration.
288
+
289
+ Args:
290
+ manifest: Manifest dict
291
+
292
+ Returns:
293
+ Normalized Traefik config dict
294
+ """
295
+ traefik = manifest.get('traefik', {})
296
+
297
+ normalized_traefik = {
298
+ 'pathPrefix': traefik.get('pathPrefix', ''),
299
+ 'host': traefik.get('host', ''),
300
+ 'priority': traefik.get('priority', TRAEFIK_DEFAULTS['priority']),
301
+ }
302
+
303
+ return normalized_traefik
304
+
305
+ def merge_manifests(base, overlay):
306
+ """
307
+ Merge two manifest dicts (for inheritance patterns).
308
+
309
+ Args:
310
+ base: Base manifest dict
311
+ overlay: Overlay manifest dict
312
+
313
+ Returns:
314
+ Merged manifest dict
315
+ """
316
+ merged = {}
317
+
318
+ # Start with base
319
+ for key, value in base.items():
320
+ merged[key] = value
321
+
322
+ # Overlay takes precedence
323
+ for key, value in overlay.items():
324
+ # Special handling for nested dicts (like traefik, envVars)
325
+ if key in merged and type(merged[key]) == "dict" and type(value) == "dict":
326
+ merged[key] = {}
327
+ for k, v in merged[key].items():
328
+ merged[key][k] = v
329
+ for k, v in value.items():
330
+ merged[key][k] = v
331
+ else:
332
+ merged[key] = value
333
+
334
+ return merged
335
+
336
+ def get_normalized_manifest(manifest, resource_path=""):
337
+ """
338
+ Convenience function to parse and normalize in one call.
339
+
340
+ Args:
341
+ manifest: Raw manifest (dict or JSON string)
342
+ resource_path: Resource directory path
343
+
344
+ Returns:
345
+ struct(
346
+ manifest=None, # Normalized manifest or None
347
+ error=None, # Error message or None
348
+ warnings=[], # List of warnings
349
+ )
350
+ """
351
+ # If it's a string, parse it
352
+ if type(manifest) == "string":
353
+ parse_result = parse(manifest, resource_path)
354
+ if parse_result.error:
355
+ return parse_result
356
+ manifest = parse_result.manifest
357
+ warnings = parse_result.warnings
358
+ else:
359
+ warnings = []
360
+
361
+ # Normalize
362
+ normalized = normalize(manifest, resource_path)
363
+
364
+ return struct(
365
+ manifest=normalized,
366
+ error=None,
367
+ warnings=warnings,
368
+ )
369
+
370
+ def get_resource_type_description(manifest):
371
+ """
372
+ Get human-readable resource type description.
373
+
374
+ Args:
375
+ manifest: Manifest dict
376
+
377
+ Returns:
378
+ String description
379
+ """
380
+ app_type = manifest.get('appType', 'unknown')
381
+ stack = manifest.get('stack', 'unknown')
382
+ name = manifest.get('appName', 'unknown')
383
+
384
+ return "{stack}/{app_type}/{name}".format(
385
+ stack=stack,
386
+ app_type=app_type,
387
+ name=name,
388
+ )
389
+
390
+ # Export parser functions
391
+ ManifestParser = struct(
392
+ parse=parse,
393
+ normalize=normalize,
394
+ extract_resource_path=extract_resource_path,
395
+ extract_stack=extract_stack_from_path,
396
+ parse_traefik=parse_traefik_config,
397
+ merge=merge_manifests,
398
+ get_normalized=get_normalized_manifest,
399
+ get_description=get_resource_type_description,
400
+ )