@mouryaamit/nx-polystack 0.0.0-stage → 1.0.1

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 (680) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -2
  3. package/USER-MANUAL.md +1968 -0
  4. package/dist/bin/cli.d.ts +1 -0
  5. package/dist/bin/cli.js +92 -0
  6. package/dist/bin/cli.js.map +1 -0
  7. package/dist/executors.json +32 -0
  8. package/dist/generators.json +47 -0
  9. package/dist/migrations.json +87 -0
  10. package/dist/runtime/env-secret.cjs +736 -0
  11. package/dist/src/cli/args.d.ts +18 -0
  12. package/dist/src/cli/args.js +67 -0
  13. package/dist/src/cli/args.js.map +1 -0
  14. package/dist/src/cli/commands/app.d.ts +3 -0
  15. package/dist/src/cli/commands/app.js +108 -0
  16. package/dist/src/cli/commands/app.js.map +1 -0
  17. package/dist/src/cli/commands/build.d.ts +8 -0
  18. package/dist/src/cli/commands/build.js +132 -0
  19. package/dist/src/cli/commands/build.js.map +1 -0
  20. package/dist/src/cli/commands/csp.d.ts +19 -0
  21. package/dist/src/cli/commands/csp.js +238 -0
  22. package/dist/src/cli/commands/csp.js.map +1 -0
  23. package/dist/src/cli/commands/encryption.d.ts +4 -0
  24. package/dist/src/cli/commands/encryption.js +261 -0
  25. package/dist/src/cli/commands/encryption.js.map +1 -0
  26. package/dist/src/cli/commands/env.d.ts +2 -0
  27. package/dist/src/cli/commands/env.js +74 -0
  28. package/dist/src/cli/commands/env.js.map +1 -0
  29. package/dist/src/cli/commands/hardening.d.ts +2 -0
  30. package/dist/src/cli/commands/hardening.js +176 -0
  31. package/dist/src/cli/commands/hardening.js.map +1 -0
  32. package/dist/src/cli/commands/index.d.ts +3 -0
  33. package/dist/src/cli/commands/index.js +45 -0
  34. package/dist/src/cli/commands/index.js.map +1 -0
  35. package/dist/src/cli/commands/infra.d.ts +25 -0
  36. package/dist/src/cli/commands/infra.js +85 -0
  37. package/dist/src/cli/commands/infra.js.map +1 -0
  38. package/dist/src/cli/commands/internal-migrate.d.ts +3 -0
  39. package/dist/src/cli/commands/internal-migrate.js +65 -0
  40. package/dist/src/cli/commands/internal-migrate.js.map +1 -0
  41. package/dist/src/cli/commands/lib.d.ts +2 -0
  42. package/dist/src/cli/commands/lib.js +70 -0
  43. package/dist/src/cli/commands/lib.js.map +1 -0
  44. package/dist/src/cli/commands/llm.d.ts +2 -0
  45. package/dist/src/cli/commands/llm.js +46 -0
  46. package/dist/src/cli/commands/llm.js.map +1 -0
  47. package/dist/src/cli/commands/migrate.d.ts +2 -0
  48. package/dist/src/cli/commands/migrate.js +230 -0
  49. package/dist/src/cli/commands/migrate.js.map +1 -0
  50. package/dist/src/cli/commands/new.d.ts +6 -0
  51. package/dist/src/cli/commands/new.js +97 -0
  52. package/dist/src/cli/commands/new.js.map +1 -0
  53. package/dist/src/cli/commands/preset.d.ts +2 -0
  54. package/dist/src/cli/commands/preset.js +47 -0
  55. package/dist/src/cli/commands/preset.js.map +1 -0
  56. package/dist/src/cli/commands/release.d.ts +3 -0
  57. package/dist/src/cli/commands/release.js +83 -0
  58. package/dist/src/cli/commands/release.js.map +1 -0
  59. package/dist/src/cli/commands/shared.d.ts +3 -0
  60. package/dist/src/cli/commands/shared.js +55 -0
  61. package/dist/src/cli/commands/shared.js.map +1 -0
  62. package/dist/src/cli/commands/update.d.ts +11 -0
  63. package/dist/src/cli/commands/update.js +120 -0
  64. package/dist/src/cli/commands/update.js.map +1 -0
  65. package/dist/src/cli/context.d.ts +18 -0
  66. package/dist/src/cli/context.js +66 -0
  67. package/dist/src/cli/context.js.map +1 -0
  68. package/dist/src/cli/exec.d.ts +9 -0
  69. package/dist/src/cli/exec.js +34 -0
  70. package/dist/src/cli/exec.js.map +1 -0
  71. package/dist/src/cli/help.d.ts +1 -0
  72. package/dist/src/cli/help.js +291 -0
  73. package/dist/src/cli/help.js.map +1 -0
  74. package/dist/src/cli/install-source.d.ts +16 -0
  75. package/dist/src/cli/install-source.js +49 -0
  76. package/dist/src/cli/install-source.js.map +1 -0
  77. package/dist/src/cli/launcher.d.ts +32 -0
  78. package/dist/src/cli/launcher.js +168 -0
  79. package/dist/src/cli/launcher.js.map +1 -0
  80. package/dist/src/cli/migrations.d.ts +25 -0
  81. package/dist/src/cli/migrations.js +35 -0
  82. package/dist/src/cli/migrations.js.map +1 -0
  83. package/dist/src/cli/run-tree.d.ts +9 -0
  84. package/dist/src/cli/run-tree.js +32 -0
  85. package/dist/src/cli/run-tree.js.map +1 -0
  86. package/dist/src/cli/types.d.ts +18 -0
  87. package/dist/src/cli/types.js +12 -0
  88. package/dist/src/cli/types.js.map +1 -0
  89. package/dist/src/cli/update-plan.d.ts +15 -0
  90. package/dist/src/cli/update-plan.js +40 -0
  91. package/dist/src/cli/update-plan.js.map +1 -0
  92. package/dist/src/cli/versions.d.ts +26 -0
  93. package/dist/src/cli/versions.js +83 -0
  94. package/dist/src/cli/versions.js.map +1 -0
  95. package/dist/src/executors/build/executor.d.ts +19 -0
  96. package/dist/src/executors/build/executor.js +251 -0
  97. package/dist/src/executors/build/executor.js.map +1 -0
  98. package/dist/src/executors/build/schema.d.ts +42 -0
  99. package/dist/src/executors/build/schema.json +104 -0
  100. package/dist/src/executors/capacitor/executor.d.ts +8 -0
  101. package/dist/src/executors/capacitor/executor.js +45 -0
  102. package/dist/src/executors/capacitor/executor.js.map +1 -0
  103. package/dist/src/executors/capacitor/schema.d.ts +10 -0
  104. package/dist/src/executors/capacitor/schema.json +24 -0
  105. package/dist/src/executors/clean/executor.d.ts +19 -0
  106. package/dist/src/executors/clean/executor.js +134 -0
  107. package/dist/src/executors/clean/executor.js.map +1 -0
  108. package/dist/src/executors/clean/schema.d.ts +6 -0
  109. package/dist/src/executors/clean/schema.json +21 -0
  110. package/dist/src/executors/flutter-build/executor.d.ts +8 -0
  111. package/dist/src/executors/flutter-build/executor.js +70 -0
  112. package/dist/src/executors/flutter-build/executor.js.map +1 -0
  113. package/dist/src/executors/flutter-build/schema.d.ts +10 -0
  114. package/dist/src/executors/flutter-build/schema.json +44 -0
  115. package/dist/src/executors/flutter-export/executor.d.ts +8 -0
  116. package/dist/src/executors/flutter-export/executor.js +36 -0
  117. package/dist/src/executors/flutter-export/executor.js.map +1 -0
  118. package/dist/src/executors/flutter-export/schema.d.ts +6 -0
  119. package/dist/src/executors/flutter-export/schema.json +28 -0
  120. package/dist/src/generators/app/files/angular/.eslintrc.json__template__ +28 -0
  121. package/dist/src/generators/app/files/angular/csp-allowlist.json__template__ +1 -0
  122. package/dist/src/generators/app/files/angular/server/README.md__template__ +31 -0
  123. package/dist/src/generators/app/files/angular/src/app/app-routing.module.ts__template__ +10 -0
  124. package/dist/src/generators/app/files/angular/src/app/app.component.html__template__ +4 -0
  125. package/dist/src/generators/app/files/angular/src/app/app.component.scss__template__ +1 -0
  126. package/dist/src/generators/app/files/angular/src/app/app.component.ts__template__ +9 -0
  127. package/dist/src/generators/app/files/angular/src/app/app.module.ts__template__ +13 -0
  128. package/dist/src/generators/app/files/angular/src/index.html__template__ +12 -0
  129. package/dist/src/generators/app/files/angular/src/main.ts__template__ +16 -0
  130. package/dist/src/generators/app/files/angular/src/styles.scss__template__ +1 -0
  131. package/dist/src/generators/app/files/angular/tsconfig.app.json__template__ +10 -0
  132. package/dist/src/generators/app/files/angular/tsconfig.json__template__ +25 -0
  133. package/dist/src/generators/app/files/angular/tsconfig.spec.json__template__ +8 -0
  134. package/dist/src/generators/app/files/flutter/.gitignore__template__ +10 -0
  135. package/dist/src/generators/app/files/flutter/analysis_options.yaml__template__ +8 -0
  136. package/dist/src/generators/app/files/flutter/lib/main.dart__template__ +23 -0
  137. package/dist/src/generators/app/files/flutter/pubspec.yaml__template__ +26 -0
  138. package/dist/src/generators/app/files/flutter/server/nginx.conf__template__ +35 -0
  139. package/dist/src/generators/app/files/ionic/.gitignore__template__ +7 -0
  140. package/dist/src/generators/app/files/ionic/capacitor.config.ts__template__ +19 -0
  141. package/dist/src/generators/app/files/ionic/package.json__template__ +14 -0
  142. package/dist/src/generators/app/files/ionic/src/app/app.component.html__template__ +3 -0
  143. package/dist/src/generators/app/files/ionic/src/app/app.component.scss__template__ +0 -0
  144. package/dist/src/generators/app/files/ionic/src/app/app.module.ts__template__ +16 -0
  145. package/dist/src/generators/app/files/ionic/src/index.html__template__ +17 -0
  146. package/dist/src/generators/app/files/ionic/src/styles.scss__template__ +12 -0
  147. package/dist/src/generators/app/generator.d.ts +15 -0
  148. package/dist/src/generators/app/generator.js +363 -0
  149. package/dist/src/generators/app/generator.js.map +1 -0
  150. package/dist/src/generators/app/schema.d.ts +19 -0
  151. package/dist/src/generators/app/schema.json +77 -0
  152. package/dist/src/generators/env/generator.d.ts +3 -0
  153. package/dist/src/generators/env/generator.js +454 -0
  154. package/dist/src/generators/env/generator.js.map +1 -0
  155. package/dist/src/generators/env/schema.d.ts +18 -0
  156. package/dist/src/generators/env/schema.json +47 -0
  157. package/dist/src/generators/infra/files/ci/commitlint/commitlint.config.js__template__ +6 -0
  158. package/dist/src/generators/infra/files/ci/common/tools/config/allowed-cycles.json__template__ +1 -0
  159. package/dist/src/generators/infra/files/ci/common/tools/scripts/check-cycles.js__template__ +201 -0
  160. package/dist/src/generators/infra/files/ci/github-actions/.github/workflows/ci.yml__template__ +68 -0
  161. package/dist/src/generators/infra/files/ci/github-actions/.github/workflows/pr-title.yml__template__ +36 -0
  162. package/dist/src/generators/infra/files/ci/jenkins/Jenkinsfile__template__ +45 -0
  163. package/dist/src/generators/infra/files/docs/.github/ISSUE_TEMPLATE/bug.yml__template__ +39 -0
  164. package/dist/src/generators/infra/files/docs/.github/ISSUE_TEMPLATE/config.yml__template__ +1 -0
  165. package/dist/src/generators/infra/files/docs/.github/ISSUE_TEMPLATE/feature.yml__template__ +23 -0
  166. package/dist/src/generators/infra/files/docs/.github/PULL_REQUEST_TEMPLATE.md__template__ +23 -0
  167. package/dist/src/generators/infra/files/docs/CODE_OF_CONDUCT.md__template__ +18 -0
  168. package/dist/src/generators/infra/files/docs/CONTRIBUTING.md__template__ +61 -0
  169. package/dist/src/generators/infra/files/docs/SECURITY.md__template__ +25 -0
  170. package/dist/src/generators/infra/files/quality/.husky/pre-push__template__ +2 -0
  171. package/dist/src/generators/infra/files/quality/.secretlintignore__template__ +7 -0
  172. package/dist/src/generators/infra/files/quality/.secretlintrc.json__template__ +7 -0
  173. package/dist/src/generators/infra/files/quality/knip.json__template__ +9 -0
  174. package/dist/src/generators/infra/files/upgrades/.github/workflows/dependency-upgrade.yml__template__ +80 -0
  175. package/dist/src/generators/infra/generator.d.ts +60 -0
  176. package/dist/src/generators/infra/generator.js +356 -0
  177. package/dist/src/generators/infra/generator.js.map +1 -0
  178. package/dist/src/generators/infra/options.d.ts +28 -0
  179. package/dist/src/generators/infra/options.js +80 -0
  180. package/dist/src/generators/infra/options.js.map +1 -0
  181. package/dist/src/generators/infra/schema.d.ts +19 -0
  182. package/dist/src/generators/infra/schema.json +59 -0
  183. package/dist/src/generators/lib/angular-lib.d.ts +27 -0
  184. package/dist/src/generators/lib/angular-lib.js +85 -0
  185. package/dist/src/generators/lib/angular-lib.js.map +1 -0
  186. package/dist/src/generators/lib/files/angular/component/src/index.ts__template__ +2 -0
  187. package/dist/src/generators/lib/files/angular/component/src/lib/__fileName__/__fileName__.component.html__template__ +1 -0
  188. package/dist/src/generators/lib/files/angular/component/src/lib/__fileName__/__fileName__.component.scss__template__ +3 -0
  189. package/dist/src/generators/lib/files/angular/component/src/lib/__fileName__/__fileName__.component.ts__template__ +9 -0
  190. package/dist/src/generators/lib/files/angular/component/src/lib/__fileName__.module.ts__template__ +11 -0
  191. package/dist/src/generators/lib/files/angular/config/.eslintrc.json__template__ +32 -0
  192. package/dist/src/generators/lib/files/angular/config/tsconfig.json__template__ +22 -0
  193. package/dist/src/generators/lib/files/angular/config/tsconfig.lib.json__template__ +12 -0
  194. package/dist/src/generators/lib/files/assets/README.md__template__ +13 -0
  195. package/dist/src/generators/lib/files/design-tokens/README.md__template__ +90 -0
  196. package/dist/src/generators/lib/files/design-tokens/generated/dart/pubspec.yaml__template__ +11 -0
  197. package/dist/src/generators/lib/files/design-tokens/src/index.ts__template__ +1 -0
  198. package/dist/src/generators/lib/files/design-tokens/style-dictionary.config.js__template__ +41 -0
  199. package/dist/src/generators/lib/files/flutter/.gitignore__template__ +7 -0
  200. package/dist/src/generators/lib/files/flutter/analysis_options.yaml__template__ +6 -0
  201. package/dist/src/generators/lib/files/flutter/lib/__snakeName__.dart__template__ +1 -0
  202. package/dist/src/generators/lib/files/flutter/lib/src/__snakeName__.dart__template__ +6 -0
  203. package/dist/src/generators/lib/files/flutter/pubspec.yaml__template__ +18 -0
  204. package/dist/src/generators/lib/files/flutter/test/__snakeName___test.dart__template__ +8 -0
  205. package/dist/src/generators/lib/files/ionic/src/index.ts__template__ +2 -0
  206. package/dist/src/generators/lib/files/ionic/src/lib/__fileName__/__fileName__.page.html__template__ +9 -0
  207. package/dist/src/generators/lib/files/ionic/src/lib/__fileName__/__fileName__.page.scss__template__ +3 -0
  208. package/dist/src/generators/lib/files/ionic/src/lib/__fileName__/__fileName__.page.ts__template__ +9 -0
  209. package/dist/src/generators/lib/files/ionic/src/lib/__fileName__.module.ts__template__ +12 -0
  210. package/dist/src/generators/lib/files/pii/README.md__template__ +35 -0
  211. package/dist/src/generators/lib/files/pii/src/index.ts__template__ +5 -0
  212. package/dist/src/generators/lib/files/pii/src/lib/pii-mask.directive.ts__template__ +30 -0
  213. package/dist/src/generators/lib/files/pii/src/lib/pii-mask.module.ts__template__ +17 -0
  214. package/dist/src/generators/lib/files/pii/src/lib/pii-mask.options.ts__template__ +6 -0
  215. package/dist/src/generators/lib/files/pii/src/lib/pii-mask.pipe.ts__template__ +14 -0
  216. package/dist/src/generators/lib/files/pii/src/lib/pii-mask.ts__template__ +117 -0
  217. package/dist/src/generators/lib/files/session/README.md__template__ +39 -0
  218. package/dist/src/generators/lib/files/session/src/index.ts__template__ +5 -0
  219. package/dist/src/generators/lib/files/session/src/lib/session-clock.ts__template__ +113 -0
  220. package/dist/src/generators/lib/files/session/src/lib/session-timeout.config.ts__template__ +8 -0
  221. package/dist/src/generators/lib/files/session/src/lib/session-timeout.module.ts__template__ +23 -0
  222. package/dist/src/generators/lib/files/session/src/lib/session-timeout.service.ts__template__ +289 -0
  223. package/dist/src/generators/lib/files/session/src/lib/session-warning/session-warning.component.html__template__ +21 -0
  224. package/dist/src/generators/lib/files/session/src/lib/session-warning/session-warning.component.scss__template__ +40 -0
  225. package/dist/src/generators/lib/files/session/src/lib/session-warning/session-warning.component.ts__template__ +105 -0
  226. package/dist/src/generators/lib/files/state/ngrx/README.md__template__ +33 -0
  227. package/dist/src/generators/lib/files/state/ngrx/src/index.ts__template__ +6 -0
  228. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__-state.module.ts__template__ +18 -0
  229. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__.actions.ts__template__ +12 -0
  230. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__.effects.ts__template__ +26 -0
  231. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__.models.ts__template__ +4 -0
  232. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__.reducer.ts__template__ +33 -0
  233. package/dist/src/generators/lib/files/state/ngrx/src/lib/__fileName__.selectors.ts__template__ +14 -0
  234. package/dist/src/generators/lib/files/state/simple-service/README.md__template__ +20 -0
  235. package/dist/src/generators/lib/files/state/simple-service/src/index.ts__template__ +2 -0
  236. package/dist/src/generators/lib/files/state/simple-service/src/lib/__fileName__.store.ts__template__ +58 -0
  237. package/dist/src/generators/lib/files/state/simple-service/src/lib/store.ts__template__ +34 -0
  238. package/dist/src/generators/lib/files/styles/README.md__template__ +39 -0
  239. package/dist/src/generators/lib/files/styles/src/_index.scss__template__ +3 -0
  240. package/dist/src/generators/lib/files/styles/src/mixins/_index.scss__template__ +13 -0
  241. package/dist/src/generators/lib/files/styles/src/themes/_index.scss__template__ +20 -0
  242. package/dist/src/generators/lib/files/styles/src/tokens/_index.scss__template__ +27 -0
  243. package/dist/src/generators/lib/files/ts/config/.eslintrc.json__template__ +10 -0
  244. package/dist/src/generators/lib/files/ts/config/tsconfig.json__template__ +14 -0
  245. package/dist/src/generators/lib/files/ts/config/tsconfig.lib.json__template__ +10 -0
  246. package/dist/src/generators/lib/files/ts/sample/src/index.ts__template__ +1 -0
  247. package/dist/src/generators/lib/files/ts/sample/src/lib/__fileName__.ts__template__ +4 -0
  248. package/dist/src/generators/lib/generator.d.ts +3 -0
  249. package/dist/src/generators/lib/generator.js +53 -0
  250. package/dist/src/generators/lib/generator.js.map +1 -0
  251. package/dist/src/generators/lib/lib-utils.d.ts +72 -0
  252. package/dist/src/generators/lib/lib-utils.js +170 -0
  253. package/dist/src/generators/lib/lib-utils.js.map +1 -0
  254. package/dist/src/generators/lib/schema.d.ts +31 -0
  255. package/dist/src/generators/lib/schema.json +63 -0
  256. package/dist/src/generators/lib/style-dictionary.d.ts +36 -0
  257. package/dist/src/generators/lib/style-dictionary.js +183 -0
  258. package/dist/src/generators/lib/style-dictionary.js.map +1 -0
  259. package/dist/src/generators/lib/types/angular.d.ts +2 -0
  260. package/dist/src/generators/lib/types/angular.js +20 -0
  261. package/dist/src/generators/lib/types/angular.js.map +1 -0
  262. package/dist/src/generators/lib/types/assets.d.ts +2 -0
  263. package/dist/src/generators/lib/types/assets.js +20 -0
  264. package/dist/src/generators/lib/types/assets.js.map +1 -0
  265. package/dist/src/generators/lib/types/design-tokens.d.ts +10 -0
  266. package/dist/src/generators/lib/types/design-tokens.js +78 -0
  267. package/dist/src/generators/lib/types/design-tokens.js.map +1 -0
  268. package/dist/src/generators/lib/types/flutter.d.ts +2 -0
  269. package/dist/src/generators/lib/types/flutter.js +28 -0
  270. package/dist/src/generators/lib/types/flutter.js.map +1 -0
  271. package/dist/src/generators/lib/types/index.d.ts +8 -0
  272. package/dist/src/generators/lib/types/index.js +31 -0
  273. package/dist/src/generators/lib/types/index.js.map +1 -0
  274. package/dist/src/generators/lib/types/ionic.d.ts +4 -0
  275. package/dist/src/generators/lib/types/ionic.js +35 -0
  276. package/dist/src/generators/lib/types/ionic.js.map +1 -0
  277. package/dist/src/generators/lib/types/pii.d.ts +3 -0
  278. package/dist/src/generators/lib/types/pii.js +19 -0
  279. package/dist/src/generators/lib/types/pii.js.map +1 -0
  280. package/dist/src/generators/lib/types/session.d.ts +3 -0
  281. package/dist/src/generators/lib/types/session.js +21 -0
  282. package/dist/src/generators/lib/types/session.js.map +1 -0
  283. package/dist/src/generators/lib/types/state.d.ts +5 -0
  284. package/dist/src/generators/lib/types/state.js +48 -0
  285. package/dist/src/generators/lib/types/state.js.map +1 -0
  286. package/dist/src/generators/lib/types/styles.d.ts +2 -0
  287. package/dist/src/generators/lib/types/styles.js +19 -0
  288. package/dist/src/generators/lib/types/styles.js.map +1 -0
  289. package/dist/src/generators/lib/types/ts.d.ts +5 -0
  290. package/dist/src/generators/lib/types/ts.js +30 -0
  291. package/dist/src/generators/lib/types/ts.js.map +1 -0
  292. package/dist/src/generators/llm/generator.d.ts +8 -0
  293. package/dist/src/generators/llm/generator.js +13 -0
  294. package/dist/src/generators/llm/generator.js.map +1 -0
  295. package/dist/src/generators/llm/schema.d.ts +4 -0
  296. package/dist/src/generators/llm/schema.json +16 -0
  297. package/dist/src/generators/migrate/adapters/angular-cli.d.ts +82 -0
  298. package/dist/src/generators/migrate/adapters/angular-cli.js +439 -0
  299. package/dist/src/generators/migrate/adapters/angular-cli.js.map +1 -0
  300. package/dist/src/generators/migrate/adapters/angular-workspace.d.ts +28 -0
  301. package/dist/src/generators/migrate/adapters/angular-workspace.js +397 -0
  302. package/dist/src/generators/migrate/adapters/angular-workspace.js.map +1 -0
  303. package/dist/src/generators/migrate/adapters/external.d.ts +23 -0
  304. package/dist/src/generators/migrate/adapters/external.js +230 -0
  305. package/dist/src/generators/migrate/adapters/external.js.map +1 -0
  306. package/dist/src/generators/migrate/adapters/flutter.d.ts +26 -0
  307. package/dist/src/generators/migrate/adapters/flutter.js +176 -0
  308. package/dist/src/generators/migrate/adapters/flutter.js.map +1 -0
  309. package/dist/src/generators/migrate/adapters/index.d.ts +34 -0
  310. package/dist/src/generators/migrate/adapters/index.js +136 -0
  311. package/dist/src/generators/migrate/adapters/index.js.map +1 -0
  312. package/dist/src/generators/migrate/adapters/ionic.d.ts +17 -0
  313. package/dist/src/generators/migrate/adapters/ionic.js +137 -0
  314. package/dist/src/generators/migrate/adapters/ionic.js.map +1 -0
  315. package/dist/src/generators/migrate/adapters/npm-workspaces.d.ts +23 -0
  316. package/dist/src/generators/migrate/adapters/npm-workspaces.js +734 -0
  317. package/dist/src/generators/migrate/adapters/npm-workspaces.js.map +1 -0
  318. package/dist/src/generators/migrate/adapters/nx-workspace.d.ts +47 -0
  319. package/dist/src/generators/migrate/adapters/nx-workspace.js +1037 -0
  320. package/dist/src/generators/migrate/adapters/nx-workspace.js.map +1 -0
  321. package/dist/src/generators/migrate/adapters/scaffold.d.ts +2 -0
  322. package/dist/src/generators/migrate/adapters/scaffold.js +200 -0
  323. package/dist/src/generators/migrate/adapters/scaffold.js.map +1 -0
  324. package/dist/src/generators/migrate/adapters/types.d.ts +184 -0
  325. package/dist/src/generators/migrate/adapters/types.js +63 -0
  326. package/dist/src/generators/migrate/adapters/types.js.map +1 -0
  327. package/dist/src/generators/migrate/angular-code-scan.d.ts +6 -0
  328. package/dist/src/generators/migrate/angular-code-scan.js +150 -0
  329. package/dist/src/generators/migrate/angular-code-scan.js.map +1 -0
  330. package/dist/src/generators/migrate/angular-config-files.d.ts +49 -0
  331. package/dist/src/generators/migrate/angular-config-files.js +158 -0
  332. package/dist/src/generators/migrate/angular-config-files.js.map +1 -0
  333. package/dist/src/generators/migrate/angular-project-json.d.ts +73 -0
  334. package/dist/src/generators/migrate/angular-project-json.js +352 -0
  335. package/dist/src/generators/migrate/angular-project-json.js.map +1 -0
  336. package/dist/src/generators/migrate/angular-workspace/aliases.d.ts +30 -0
  337. package/dist/src/generators/migrate/angular-workspace/aliases.js +73 -0
  338. package/dist/src/generators/migrate/angular-workspace/aliases.js.map +1 -0
  339. package/dist/src/generators/migrate/angular-workspace/eslint.d.ts +8 -0
  340. package/dist/src/generators/migrate/angular-workspace/eslint.js +38 -0
  341. package/dist/src/generators/migrate/angular-workspace/eslint.js.map +1 -0
  342. package/dist/src/generators/migrate/angular-workspace/ng-package.d.ts +4 -0
  343. package/dist/src/generators/migrate/angular-workspace/ng-package.js +16 -0
  344. package/dist/src/generators/migrate/angular-workspace/ng-package.js.map +1 -0
  345. package/dist/src/generators/migrate/angular-workspace/source.d.ts +15 -0
  346. package/dist/src/generators/migrate/angular-workspace/source.js +108 -0
  347. package/dist/src/generators/migrate/angular-workspace/source.js.map +1 -0
  348. package/dist/src/generators/migrate/angular17.d.ts +45 -0
  349. package/dist/src/generators/migrate/angular17.js +495 -0
  350. package/dist/src/generators/migrate/angular17.js.map +1 -0
  351. package/dist/src/generators/migrate/batch.d.ts +29 -0
  352. package/dist/src/generators/migrate/batch.js +211 -0
  353. package/dist/src/generators/migrate/batch.js.map +1 -0
  354. package/dist/src/generators/migrate/copy.d.ts +60 -0
  355. package/dist/src/generators/migrate/copy.js +224 -0
  356. package/dist/src/generators/migrate/copy.js.map +1 -0
  357. package/dist/src/generators/migrate/dependencies.d.ts +38 -0
  358. package/dist/src/generators/migrate/dependencies.js +196 -0
  359. package/dist/src/generators/migrate/dependencies.js.map +1 -0
  360. package/dist/src/generators/migrate/generator.d.ts +9 -0
  361. package/dist/src/generators/migrate/generator.js +347 -0
  362. package/dist/src/generators/migrate/generator.js.map +1 -0
  363. package/dist/src/generators/migrate/imports/rewrite.d.ts +46 -0
  364. package/dist/src/generators/migrate/imports/rewrite.js +382 -0
  365. package/dist/src/generators/migrate/imports/rewrite.js.map +1 -0
  366. package/dist/src/generators/migrate/ionic/capacitor-config.d.ts +24 -0
  367. package/dist/src/generators/migrate/ionic/capacitor-config.js +113 -0
  368. package/dist/src/generators/migrate/ionic/capacitor-config.js.map +1 -0
  369. package/dist/src/generators/migrate/ionic/packages.d.ts +34 -0
  370. package/dist/src/generators/migrate/ionic/packages.js +92 -0
  371. package/dist/src/generators/migrate/ionic/packages.js.map +1 -0
  372. package/dist/src/generators/migrate/ionic/shape.d.ts +32 -0
  373. package/dist/src/generators/migrate/ionic/shape.js +221 -0
  374. package/dist/src/generators/migrate/ionic/shape.js.map +1 -0
  375. package/dist/src/generators/migrate/ionic/skip.d.ts +3 -0
  376. package/dist/src/generators/migrate/ionic/skip.js +25 -0
  377. package/dist/src/generators/migrate/ionic/skip.js.map +1 -0
  378. package/dist/src/generators/migrate/names.d.ts +3 -0
  379. package/dist/src/generators/migrate/names.js +21 -0
  380. package/dist/src/generators/migrate/names.js.map +1 -0
  381. package/dist/src/generators/migrate/npm-deps.d.ts +28 -0
  382. package/dist/src/generators/migrate/npm-deps.js +63 -0
  383. package/dist/src/generators/migrate/npm-deps.js.map +1 -0
  384. package/dist/src/generators/migrate/npm-workspaces/pnpm-yaml.d.ts +10 -0
  385. package/dist/src/generators/migrate/npm-workspaces/pnpm-yaml.js +246 -0
  386. package/dist/src/generators/migrate/npm-workspaces/pnpm-yaml.js.map +1 -0
  387. package/dist/src/generators/migrate/npm-workspaces/source.d.ts +46 -0
  388. package/dist/src/generators/migrate/npm-workspaces/source.js +253 -0
  389. package/dist/src/generators/migrate/npm-workspaces/source.js.map +1 -0
  390. package/dist/src/generators/migrate/nx/build-scripts.d.ts +22 -0
  391. package/dist/src/generators/migrate/nx/build-scripts.js +147 -0
  392. package/dist/src/generators/migrate/nx/build-scripts.js.map +1 -0
  393. package/dist/src/generators/migrate/nx/detect.d.ts +3 -0
  394. package/dist/src/generators/migrate/nx/detect.js +43 -0
  395. package/dist/src/generators/migrate/nx/detect.js.map +1 -0
  396. package/dist/src/generators/migrate/nx/env-encryption.d.ts +35 -0
  397. package/dist/src/generators/migrate/nx/env-encryption.js +423 -0
  398. package/dist/src/generators/migrate/nx/env-encryption.js.map +1 -0
  399. package/dist/src/generators/migrate/nx/rewrite.d.ts +27 -0
  400. package/dist/src/generators/migrate/nx/rewrite.js +223 -0
  401. package/dist/src/generators/migrate/nx/rewrite.js.map +1 -0
  402. package/dist/src/generators/migrate/nx/selection.d.ts +25 -0
  403. package/dist/src/generators/migrate/nx/selection.js +173 -0
  404. package/dist/src/generators/migrate/nx/selection.js.map +1 -0
  405. package/dist/src/generators/migrate/nx/shared-folders.d.ts +58 -0
  406. package/dist/src/generators/migrate/nx/shared-folders.js +239 -0
  407. package/dist/src/generators/migrate/nx/shared-folders.js.map +1 -0
  408. package/dist/src/generators/migrate/nx/workspace-source.d.ts +58 -0
  409. package/dist/src/generators/migrate/nx/workspace-source.js +275 -0
  410. package/dist/src/generators/migrate/nx/workspace-source.js.map +1 -0
  411. package/dist/src/generators/migrate/pnpm.d.ts +42 -0
  412. package/dist/src/generators/migrate/pnpm.js +132 -0
  413. package/dist/src/generators/migrate/pnpm.js.map +1 -0
  414. package/dist/src/generators/migrate/report.d.ts +21 -0
  415. package/dist/src/generators/migrate/report.js +243 -0
  416. package/dist/src/generators/migrate/report.js.map +1 -0
  417. package/dist/src/generators/migrate/rollback/manifest.d.ts +84 -0
  418. package/dist/src/generators/migrate/rollback/manifest.js +162 -0
  419. package/dist/src/generators/migrate/rollback/manifest.js.map +1 -0
  420. package/dist/src/generators/migrate/rollback/recording-tree.d.ts +19 -0
  421. package/dist/src/generators/migrate/rollback/recording-tree.js +87 -0
  422. package/dist/src/generators/migrate/rollback/recording-tree.js.map +1 -0
  423. package/dist/src/generators/migrate/rollback/rollback.d.ts +29 -0
  424. package/dist/src/generators/migrate/rollback/rollback.js +271 -0
  425. package/dist/src/generators/migrate/rollback/rollback.js.map +1 -0
  426. package/dist/src/generators/migrate/schema.d.ts +41 -0
  427. package/dist/src/generators/migrate/schema.json +85 -0
  428. package/dist/src/generators/migrate/source.d.ts +26 -0
  429. package/dist/src/generators/migrate/source.js +70 -0
  430. package/dist/src/generators/migrate/source.js.map +1 -0
  431. package/dist/src/generators/preset/files/root/.editorconfig__template__ +15 -0
  432. package/dist/src/generators/preset/files/root/.eslintignore__template__ +2 -0
  433. package/dist/src/generators/preset/files/root/.eslintrc.json__template__ +38 -0
  434. package/dist/src/generators/preset/files/root/.gitattributes__template__ +12 -0
  435. package/dist/src/generators/preset/files/root/.gitignore__template__ +9 -0
  436. package/dist/src/generators/preset/files/root/.husky/commit-msg__template__ +1 -0
  437. package/dist/src/generators/preset/files/root/.husky/pre-commit__template__ +1 -0
  438. package/dist/src/generators/preset/files/root/.npmrc__template__ +4 -0
  439. package/dist/src/generators/preset/files/root/.nvmrc__template__ +1 -0
  440. package/dist/src/generators/preset/files/root/.prettierignore__template__ +6 -0
  441. package/dist/src/generators/preset/files/root/.prettierrc__template__ +7 -0
  442. package/dist/src/generators/preset/files/root/commitlint.config.js__template__ +6 -0
  443. package/dist/src/generators/preset/files/root/nx.json__template__ +30 -0
  444. package/dist/src/generators/preset/files/root/package.json__template__ +34 -0
  445. package/dist/src/generators/preset/files/root/tools/config/sri-cdn-allowlist.json__template__ +1 -0
  446. package/dist/src/generators/preset/files/root/tsconfig.base.json__template__ +18 -0
  447. package/dist/src/generators/preset/generator.d.ts +11 -0
  448. package/dist/src/generators/preset/generator.js +91 -0
  449. package/dist/src/generators/preset/generator.js.map +1 -0
  450. package/dist/src/generators/preset/schema.d.ts +20 -0
  451. package/dist/src/generators/preset/schema.json +86 -0
  452. package/dist/src/generators/shared-libs/generator.d.ts +4 -0
  453. package/dist/src/generators/shared-libs/generator.js +60 -0
  454. package/dist/src/generators/shared-libs/generator.js.map +1 -0
  455. package/dist/src/generators/shared-libs/schema.d.ts +6 -0
  456. package/dist/src/generators/shared-libs/schema.json +21 -0
  457. package/dist/src/index.d.ts +16 -0
  458. package/dist/src/index.js +20 -0
  459. package/dist/src/index.js.map +1 -0
  460. package/dist/src/lib/csp/allowlist.d.ts +64 -0
  461. package/dist/src/lib/csp/allowlist.js +126 -0
  462. package/dist/src/lib/csp/allowlist.js.map +1 -0
  463. package/dist/src/lib/csp/import.d.ts +52 -0
  464. package/dist/src/lib/csp/import.js +291 -0
  465. package/dist/src/lib/csp/import.js.map +1 -0
  466. package/dist/src/lib/csp/render.d.ts +19 -0
  467. package/dist/src/lib/csp/render.js +116 -0
  468. package/dist/src/lib/csp/render.js.map +1 -0
  469. package/dist/src/lib/env/derive.d.ts +38 -0
  470. package/dist/src/lib/env/derive.js +115 -0
  471. package/dist/src/lib/env/derive.js.map +1 -0
  472. package/dist/src/lib/env-encryption/backup.d.ts +40 -0
  473. package/dist/src/lib/env-encryption/backup.js +234 -0
  474. package/dist/src/lib/env-encryption/backup.js.map +1 -0
  475. package/dist/src/lib/env-encryption/config.d.ts +50 -0
  476. package/dist/src/lib/env-encryption/config.js +173 -0
  477. package/dist/src/lib/env-encryption/config.js.map +1 -0
  478. package/dist/src/lib/env-encryption/domains.d.ts +9 -0
  479. package/dist/src/lib/env-encryption/domains.js +52 -0
  480. package/dist/src/lib/env-encryption/domains.js.map +1 -0
  481. package/dist/src/lib/env-encryption/encrypt.d.ts +48 -0
  482. package/dist/src/lib/env-encryption/encrypt.js +407 -0
  483. package/dist/src/lib/env-encryption/encrypt.js.map +1 -0
  484. package/dist/src/lib/env-encryption/env-file.d.ts +72 -0
  485. package/dist/src/lib/env-encryption/env-file.js +395 -0
  486. package/dist/src/lib/env-encryption/env-file.js.map +1 -0
  487. package/dist/src/lib/env-encryption/gcm.d.ts +51 -0
  488. package/dist/src/lib/env-encryption/gcm.js +76 -0
  489. package/dist/src/lib/env-encryption/gcm.js.map +1 -0
  490. package/dist/src/lib/env-encryption/key-material.d.ts +53 -0
  491. package/dist/src/lib/env-encryption/key-material.js +148 -0
  492. package/dist/src/lib/env-encryption/key-material.js.map +1 -0
  493. package/dist/src/lib/env-encryption/placeholders.d.ts +15 -0
  494. package/dist/src/lib/env-encryption/placeholders.js +93 -0
  495. package/dist/src/lib/env-encryption/placeholders.js.map +1 -0
  496. package/dist/src/lib/env-encryption/prepare.d.ts +43 -0
  497. package/dist/src/lib/env-encryption/prepare.js +245 -0
  498. package/dist/src/lib/env-encryption/prepare.js.map +1 -0
  499. package/dist/src/lib/env-encryption/sensitive.d.ts +2 -0
  500. package/dist/src/lib/env-encryption/sensitive.js +180 -0
  501. package/dist/src/lib/env-encryption/sensitive.js.map +1 -0
  502. package/dist/src/lib/env-encryption/stamp.d.ts +2 -0
  503. package/dist/src/lib/env-encryption/stamp.js +52 -0
  504. package/dist/src/lib/env-encryption/stamp.js.map +1 -0
  505. package/dist/src/lib/env-encryption/switch-gcm.d.ts +43 -0
  506. package/dist/src/lib/env-encryption/switch-gcm.js +371 -0
  507. package/dist/src/lib/env-encryption/switch-gcm.js.map +1 -0
  508. package/dist/src/lib/env-encryption/workspace.d.ts +10 -0
  509. package/dist/src/lib/env-encryption/workspace.js +48 -0
  510. package/dist/src/lib/env-encryption/workspace.js.map +1 -0
  511. package/dist/src/lib/hardening/files.d.ts +17 -0
  512. package/dist/src/lib/hardening/files.js +43 -0
  513. package/dist/src/lib/hardening/files.js.map +1 -0
  514. package/dist/src/lib/hardening/integrity.d.ts +24 -0
  515. package/dist/src/lib/hardening/integrity.js +112 -0
  516. package/dist/src/lib/hardening/integrity.js.map +1 -0
  517. package/dist/src/lib/hardening/leak-check.d.ts +15 -0
  518. package/dist/src/lib/hardening/leak-check.js +100 -0
  519. package/dist/src/lib/hardening/leak-check.js.map +1 -0
  520. package/dist/src/lib/hardening/ngsw.d.ts +7 -0
  521. package/dist/src/lib/hardening/ngsw.js +55 -0
  522. package/dist/src/lib/hardening/ngsw.js.map +1 -0
  523. package/dist/src/lib/hardening/obfuscate.d.ts +36 -0
  524. package/dist/src/lib/hardening/obfuscate.js +153 -0
  525. package/dist/src/lib/hardening/obfuscate.js.map +1 -0
  526. package/dist/src/lib/hardening/options.d.ts +36 -0
  527. package/dist/src/lib/hardening/options.js +143 -0
  528. package/dist/src/lib/hardening/options.js.map +1 -0
  529. package/dist/src/lib/hardening/source-maps.d.ts +7 -0
  530. package/dist/src/lib/hardening/source-maps.js +37 -0
  531. package/dist/src/lib/hardening/source-maps.js.map +1 -0
  532. package/dist/src/lib/hardening/strip.d.ts +55 -0
  533. package/dist/src/lib/hardening/strip.js +178 -0
  534. package/dist/src/lib/hardening/strip.js.map +1 -0
  535. package/dist/src/lib/helpers/encrypt-env.d.ts +13 -0
  536. package/dist/src/lib/helpers/encrypt-env.js +33 -0
  537. package/dist/src/lib/helpers/encrypt-env.js.map +1 -0
  538. package/dist/src/lib/helpers/inject-meta.d.ts +14 -0
  539. package/dist/src/lib/helpers/inject-meta.js +49 -0
  540. package/dist/src/lib/helpers/inject-meta.js.map +1 -0
  541. package/dist/src/lib/helpers/inject-nonce.d.ts +7 -0
  542. package/dist/src/lib/helpers/inject-nonce.js +59 -0
  543. package/dist/src/lib/helpers/inject-nonce.js.map +1 -0
  544. package/dist/src/lib/helpers/inject-sri.d.ts +11 -0
  545. package/dist/src/lib/helpers/inject-sri.js +92 -0
  546. package/dist/src/lib/helpers/inject-sri.js.map +1 -0
  547. package/dist/src/lib/helpers/strip-exif.d.ts +9 -0
  548. package/dist/src/lib/helpers/strip-exif.js +52 -0
  549. package/dist/src/lib/helpers/strip-exif.js.map +1 -0
  550. package/dist/src/lib/release/plan.d.ts +45 -0
  551. package/dist/src/lib/release/plan.js +76 -0
  552. package/dist/src/lib/release/plan.js.map +1 -0
  553. package/dist/src/lib/release/run.d.ts +46 -0
  554. package/dist/src/lib/release/run.js +160 -0
  555. package/dist/src/lib/release/run.js.map +1 -0
  556. package/dist/src/lib/utils/angular-deps.d.ts +22 -0
  557. package/dist/src/lib/utils/angular-deps.js +108 -0
  558. package/dist/src/lib/utils/angular-deps.js.map +1 -0
  559. package/dist/src/lib/utils/angular-project.d.ts +52 -0
  560. package/dist/src/lib/utils/angular-project.js +168 -0
  561. package/dist/src/lib/utils/angular-project.js.map +1 -0
  562. package/dist/src/lib/utils/app-dir.d.ts +17 -0
  563. package/dist/src/lib/utils/app-dir.js +52 -0
  564. package/dist/src/lib/utils/app-dir.js.map +1 -0
  565. package/dist/src/lib/utils/base-href.d.ts +26 -0
  566. package/dist/src/lib/utils/base-href.js +60 -0
  567. package/dist/src/lib/utils/base-href.js.map +1 -0
  568. package/dist/src/lib/utils/ci-resolve.d.ts +10 -0
  569. package/dist/src/lib/utils/ci-resolve.js +50 -0
  570. package/dist/src/lib/utils/ci-resolve.js.map +1 -0
  571. package/dist/src/lib/utils/csp-nonce.d.ts +34 -0
  572. package/dist/src/lib/utils/csp-nonce.js +142 -0
  573. package/dist/src/lib/utils/csp-nonce.js.map +1 -0
  574. package/dist/src/lib/utils/dependencies.d.ts +25 -0
  575. package/dist/src/lib/utils/dependencies.js +71 -0
  576. package/dist/src/lib/utils/dependencies.js.map +1 -0
  577. package/dist/src/lib/utils/devkit-deps.d.ts +19 -0
  578. package/dist/src/lib/utils/devkit-deps.js +34 -0
  579. package/dist/src/lib/utils/devkit-deps.js.map +1 -0
  580. package/dist/src/lib/utils/env-files.d.ts +18 -0
  581. package/dist/src/lib/utils/env-files.js +41 -0
  582. package/dist/src/lib/utils/env-files.js.map +1 -0
  583. package/dist/src/lib/utils/filesystem.d.ts +7 -0
  584. package/dist/src/lib/utils/filesystem.js +20 -0
  585. package/dist/src/lib/utils/filesystem.js.map +1 -0
  586. package/dist/src/lib/utils/flutter-web.d.ts +7 -0
  587. package/dist/src/lib/utils/flutter-web.js +56 -0
  588. package/dist/src/lib/utils/flutter-web.js.map +1 -0
  589. package/dist/src/lib/utils/knip.d.ts +16 -0
  590. package/dist/src/lib/utils/knip.js +71 -0
  591. package/dist/src/lib/utils/knip.js.map +1 -0
  592. package/dist/src/lib/utils/lint-staged.d.ts +5 -0
  593. package/dist/src/lib/utils/lint-staged.js +34 -0
  594. package/dist/src/lib/utils/lint-staged.js.map +1 -0
  595. package/dist/src/lib/utils/llm-block.d.ts +88 -0
  596. package/dist/src/lib/utils/llm-block.js +457 -0
  597. package/dist/src/lib/utils/llm-block.js.map +1 -0
  598. package/dist/src/lib/utils/node-engine.d.ts +9 -0
  599. package/dist/src/lib/utils/node-engine.js +63 -0
  600. package/dist/src/lib/utils/node-engine.js.map +1 -0
  601. package/dist/src/lib/utils/npm-scripts.d.ts +7 -0
  602. package/dist/src/lib/utils/npm-scripts.js +28 -0
  603. package/dist/src/lib/utils/npm-scripts.js.map +1 -0
  604. package/dist/src/lib/utils/nx-targets.d.ts +3 -0
  605. package/dist/src/lib/utils/nx-targets.js +25 -0
  606. package/dist/src/lib/utils/nx-targets.js.map +1 -0
  607. package/dist/src/lib/utils/project-json-files.d.ts +23 -0
  608. package/dist/src/lib/utils/project-json-files.js +73 -0
  609. package/dist/src/lib/utils/project-json-files.js.map +1 -0
  610. package/dist/src/lib/utils/quality.d.ts +71 -0
  611. package/dist/src/lib/utils/quality.js +295 -0
  612. package/dist/src/lib/utils/quality.js.map +1 -0
  613. package/dist/src/lib/utils/serve-port.d.ts +28 -0
  614. package/dist/src/lib/utils/serve-port.js +73 -0
  615. package/dist/src/lib/utils/serve-port.js.map +1 -0
  616. package/dist/src/lib/utils/shared-libs.d.ts +37 -0
  617. package/dist/src/lib/utils/shared-libs.js +152 -0
  618. package/dist/src/lib/utils/shared-libs.js.map +1 -0
  619. package/dist/src/lib/utils/ts-paths.d.ts +3 -0
  620. package/dist/src/lib/utils/ts-paths.js +31 -0
  621. package/dist/src/lib/utils/ts-paths.js.map +1 -0
  622. package/dist/src/lib/utils/workspace.d.ts +3 -0
  623. package/dist/src/lib/utils/workspace.js +15 -0
  624. package/dist/src/lib/utils/workspace.js.map +1 -0
  625. package/dist/src/migrate-sdk.d.ts +31 -0
  626. package/dist/src/migrate-sdk.js +35 -0
  627. package/dist/src/migrate-sdk.js.map +1 -0
  628. package/dist/src/migrations/add-csp-nonce-import/add-csp-nonce-import.d.ts +2 -0
  629. package/dist/src/migrations/add-csp-nonce-import/add-csp-nonce-import.js +40 -0
  630. package/dist/src/migrations/add-csp-nonce-import/add-csp-nonce-import.js.map +1 -0
  631. package/dist/src/migrations/add-executor-peers/add-executor-peers.d.ts +6 -0
  632. package/dist/src/migrations/add-executor-peers/add-executor-peers.js +21 -0
  633. package/dist/src/migrations/add-executor-peers/add-executor-peers.js.map +1 -0
  634. package/dist/src/migrations/add-lib-build-dependencies/add-lib-build-dependencies.d.ts +7 -0
  635. package/dist/src/migrations/add-lib-build-dependencies/add-lib-build-dependencies.js +47 -0
  636. package/dist/src/migrations/add-lib-build-dependencies/add-lib-build-dependencies.js.map +1 -0
  637. package/dist/src/migrations/add-lint-dependencies/add-lint-dependencies.d.ts +6 -0
  638. package/dist/src/migrations/add-lint-dependencies/add-lint-dependencies.js +27 -0
  639. package/dist/src/migrations/add-lint-dependencies/add-lint-dependencies.js.map +1 -0
  640. package/dist/src/migrations/add-lint-staged-config/add-lint-staged-config.d.ts +7 -0
  641. package/dist/src/migrations/add-lint-staged-config/add-lint-staged-config.js +22 -0
  642. package/dist/src/migrations/add-lint-staged-config/add-lint-staged-config.js.map +1 -0
  643. package/dist/src/migrations/angular-release-target/angular-release-target.d.ts +3 -0
  644. package/dist/src/migrations/angular-release-target/angular-release-target.js +80 -0
  645. package/dist/src/migrations/angular-release-target/angular-release-target.js.map +1 -0
  646. package/dist/src/migrations/app-clean-and-port/app-clean-and-port.d.ts +7 -0
  647. package/dist/src/migrations/app-clean-and-port/app-clean-and-port.js +89 -0
  648. package/dist/src/migrations/app-clean-and-port/app-clean-and-port.js.map +1 -0
  649. package/dist/src/migrations/env-encryption-config/env-encryption-config.d.ts +7 -0
  650. package/dist/src/migrations/env-encryption-config/env-encryption-config.js +42 -0
  651. package/dist/src/migrations/env-encryption-config/env-encryption-config.js.map +1 -0
  652. package/dist/src/migrations/env-encryption-key-sources/env-encryption-key-sources.d.ts +3 -0
  653. package/dist/src/migrations/env-encryption-key-sources/env-encryption-key-sources.js +15 -0
  654. package/dist/src/migrations/env-encryption-key-sources/env-encryption-key-sources.js.map +1 -0
  655. package/dist/src/migrations/fix-lint-script/fix-lint-script.d.ts +7 -0
  656. package/dist/src/migrations/fix-lint-script/fix-lint-script.js +27 -0
  657. package/dist/src/migrations/fix-lint-script/fix-lint-script.js.map +1 -0
  658. package/dist/src/migrations/flutter-web-platform/flutter-web-platform.d.ts +8 -0
  659. package/dist/src/migrations/flutter-web-platform/flutter-web-platform.js +35 -0
  660. package/dist/src/migrations/flutter-web-platform/flutter-web-platform.js.map +1 -0
  661. package/dist/src/migrations/plugin-repo-dev/plugin-repo-dev.d.ts +9 -0
  662. package/dist/src/migrations/plugin-repo-dev/plugin-repo-dev.js +42 -0
  663. package/dist/src/migrations/plugin-repo-dev/plugin-repo-dev.js.map +1 -0
  664. package/dist/src/migrations/prepush-audit-warn-only/prepush-audit-warn-only.d.ts +8 -0
  665. package/dist/src/migrations/prepush-audit-warn-only/prepush-audit-warn-only.js +30 -0
  666. package/dist/src/migrations/prepush-audit-warn-only/prepush-audit-warn-only.js.map +1 -0
  667. package/dist/src/migrations/quality-checks/quality-checks.d.ts +7 -0
  668. package/dist/src/migrations/quality-checks/quality-checks.js +46 -0
  669. package/dist/src/migrations/quality-checks/quality-checks.js.map +1 -0
  670. package/dist/src/migrations/release-hardening/release-hardening.d.ts +8 -0
  671. package/dist/src/migrations/release-hardening/release-hardening.js +98 -0
  672. package/dist/src/migrations/release-hardening/release-hardening.js.map +1 -0
  673. package/dist/src/migrations/sharp-security-update/sharp-security-update.d.ts +10 -0
  674. package/dist/src/migrations/sharp-security-update/sharp-security-update.js +40 -0
  675. package/dist/src/migrations/sharp-security-update/sharp-security-update.js.map +1 -0
  676. package/migrate/package.json +5 -0
  677. package/package.json +120 -4
  678. package/runtime/csp-nonce.js +109 -0
  679. package/runtime/env-secret.d.ts +63 -0
  680. package/runtime/env-secret.mjs +698 -0
package/USER-MANUAL.md ADDED
@@ -0,0 +1,1968 @@
1
+ # @mouryaamit/nx-polystack — User Manual
2
+
3
+ **Version:** v0.4.0
4
+ **CLI binary:** `pstack`
5
+ **Audience:** Developers installing or using the package from npm
6
+
7
+ ---
8
+
9
+ ## Table of contents
10
+
11
+ 1. [Overview](#1-overview)
12
+ 2. [Installation](#2-installation)
13
+ 3. [pstack CLI — quick reference](#3-pstack-cli--quick-reference)
14
+ - 3a. [pstack new — create a workspace](#3a-pstack-new--create-a-workspace)
15
+ - 3b. [pstack update — upgrade a workspace](#3b-pstack-update--upgrade-a-workspace)
16
+ - 3c. [pstack infra — repo docs, CI gates, quality checks](#3c-pstack-infra--repo-docs-ci-gates-quality-checks)
17
+ 4. [pstack preset — bootstrap a workspace](#4-pstack-preset--bootstrap-a-workspace)
18
+ 5. [pstack app — scaffold an application](#5-pstack-app--scaffold-an-application)
19
+ 6. [Nx plugin usage — generators](#6-nx-plugin-usage--generators)
20
+ 7. [Nx plugin usage — executors](#7-nx-plugin-usage--executors)
21
+ 8. [Helper modules](#8-helper-modules)
22
+ 9. [Release packaging](#9-release-packaging)
23
+ 10. [Troubleshooting](#10-troubleshooting)
24
+
25
+ ---
26
+
27
+ ## 1. Overview
28
+
29
+ `@mouryaamit/nx-polystack` is a reusable Nx plugin for scaffolding multi-technology monorepos
30
+ that target Angular, Ionic, Flutter, Android, and iOS from a single workspace. It ships:
31
+
32
+ | Feature | Available |
33
+ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
34
+ | `pstack` CLI binary — `preset` and `app` commands | v0.1.0 |
35
+ | `:preset` generator — workspace root skeleton | v0.1.0 |
36
+ | `:app --type=angular` generator — Angular 15 SPA shell | v0.1.0 |
37
+ | `:app --type=flutter` generator — Flutter project shell | v0.1.0 |
38
+ | `:build` executor — full Angular/Ionic build pipeline | v0.1.0 |
39
+ | `:flutter-build` executor — Flutter CLI wrapper | v0.1.0 |
40
+ | `:flutter-export` executor — FlutterFlow export integration | v0.1.0 |
41
+ | Helper library — encrypt-env, inject-meta, inject-nonce, inject-sri, strip-exif, ci-resolve | v0.1.0 |
42
+ | Global install (GitHub release asset) with delegation to the workspace copy | v0.3.0 |
43
+ | `pstack new <dir>` — create a workspace | v0.3.0 |
44
+ | `pstack update` — bump the pinned tag and run migrations | v0.3.0 |
45
+ | Migration runner (`migrations.json`, hidden `pstack _migrate`) | v0.3.0 |
46
+ | Angular apps build: `build` = Angular builder, `release` = hardened pipeline | v0.4.0 |
47
+ | Angular 15 (`~15.2.0`) added to `package.json` when the workspace has none | v0.4.0 |
48
+ | `:build` executor options `buildTarget` / `buildConfiguration`, custom envs (QA) | v0.4.0 |
49
+ | `angular-release-target` migration for apps generated by v0.3.x | v0.4.0 |
50
+ | Lint packages in new workspaces; missing Angular build/lint packages filled in per package | v0.4.1 |
51
+ | `:app --type=ionic` — Ionic 7 + Capacitor 5 app; `:capacitor` executor | v0.5.0 |
52
+ | Release hardening: leak check, source-map guard, strip comments, drop console (UAT/PROD) | v0.29.0 |
53
+ | Opt-in obfuscation, SRI for every chunk, runtime integrity check, ngsw hashes; `pstack hardening` | v0.30.0 |
54
+ | Obfuscation levels (light, medium, strong) and `obfuscateOptions` overrides | v0.31.0 |
55
+ | `pstack build --env=<env>` for all apps with a summary; base href per configuration (`pstack app --base-href`, `pstack release`) | v0.32.0 |
56
+ | `pstack csp`: `.htaccess` and `nginx.conf` from `csp-allowlist.json`, strict CSP with a per-request nonce (Apache SSI, Nginx sub_filter) | v0.33.0 |
57
+ | `pstack env --name=<env> --app=<a,b>\|--all`: add an environment later, copied from an existing one (placeholders for secrets, release config, Flutter, scripts) | v0.34.0 |
58
+ | App options: free dev-server port / `--port`, `clean` target, shared assets and styles (`pstack shared`), `--env-layout=per-env` | v0.35.0 |
59
+ | Quality: `typecheck` target and CI step, import/unused-imports ESLint warnings, non-blocking lint-staged (`pstack infra --lint-staged`) | v0.36.0 |
60
+ | Lib starters: `pstack lib --type=session` (idle/session timeout, cross-tab) and `--type=pii` (masking pipe and directive) | v0.37.0 |
61
+ | `pstack csp --import`: merge an existing policy (.htaccess, nginx.conf, header value, JSON) into csp-allowlist.json | v0.38.0 |
62
+
63
+ ---
64
+
65
+ ## 2. Installation
66
+
67
+ ### Option A — global install (recommended)
68
+
69
+ ```bash
70
+ npm i -g @mouryaamit/nx-polystack
71
+ pstack --version
72
+ pstack --help
73
+ ```
74
+
75
+ Requires npm 7+, which installs the `nx` and `@nx/devkit` peer dependencies next to the global package.
76
+
77
+ Note: `npm install` inside a new workspace (run by `pstack new`) downloads sharp's prebuilt binaries, so it needs network access.
78
+
79
+ ### Option B — npx (no install)
80
+
81
+ ```bash
82
+ npx --package=@mouryaamit/nx-polystack pstack new my-workspace
83
+ ```
84
+
85
+ ### Option C — dev dependency in a workspace
86
+
87
+ Add the plugin to an existing Nx workspace so Nx can discover its generators and executors:
88
+
89
+ ```bash
90
+ npm install --save-dev --save-exact @mouryaamit/nx-polystack
91
+ npx nx list @mouryaamit/nx-polystack
92
+ ```
93
+
94
+ ### System requirements
95
+
96
+ | Requirement | Version |
97
+ | --------------------------- | ------- |
98
+ | Node | 20.x |
99
+ | npm | 10+ |
100
+ | Nx (workspace install only) | 17.x |
101
+
102
+ ---
103
+
104
+ ## 3. pstack CLI — quick reference
105
+
106
+ ```
107
+ USAGE
108
+ pstack <command> [options]
109
+
110
+ COMMANDS
111
+ new <dir> Create a new polystack workspace in <dir> (installs deps, initialises git)
112
+ update Upgrade this workspace's nx-polystack version and run its migrations
113
+ preset Bootstrap a workspace root skeleton in the current directory
114
+ app Scaffold a new application into an existing workspace
115
+ env Add an environment to some or all apps later, copied from an existing one
116
+ (env file, build/serve/release configurations, Flutter env, npm scripts)
117
+ llm Write or refresh the generated workspace block in CLAUDE.md, AGENTS.md and
118
+ .github/copilot-instructions.md (app/lib/env refresh it automatically)
119
+ migrate Copy an existing project into the workspace, source never modified: a standalone
120
+ Angular CLI, Ionic/Capacitor or Flutter app (apps/<name>), the apps and libraries
121
+ of a multi-project Angular CLI repo (apps/, libs/), the Angular, Ionic and
122
+ Flutter projects of an Nx 15-17 workspace (same paths, names and aliases), or the
123
+ app and TypeScript library packages of an npm, Yarn or pnpm workspaces repo
124
+ (apps/, libs/)
125
+ infra Add repo docs, CI gates (affected lint/test/build, dependency cycles), quality
126
+ checks (knip, pre-push audit + secret scan) and a dependency-upgrade workflow
127
+
128
+ OPTIONS — new / preset
129
+ --npmScope=<scope> npm scope for the workspace (default: mouryaamit)
130
+ --baseBranch=<branch> Default git branch (default: master)
131
+ --infra=<parts> Run pstack infra with these parts: docs,ci,quality,upgrades | all |
132
+ none (default: all)
133
+ --ci=<providers> CI for the infra ci part: github-actions | jenkins (comma-separated;
134
+ default: github-actions)
135
+ --ci-cache, --flutter=<mode>, --upgrade-schedule=<s>, --upgrade-scope=<s>
136
+ passed to pstack infra
137
+ --llm=<tools> AI-assistant files, as pstack llm: claude | agents | copilot
138
+ (codex, openai-gpt → agents; comma-separated)
139
+ --projectDescription=<text> Short project description
140
+ --skipFormat Skip Prettier format pass
141
+ --skip-install new only — do not run npm install
142
+ --skip-git new only — do not initialise git
143
+ --force new only — allow creating inside another Nx workspace
144
+
145
+ OPTIONS — update
146
+ --to=<version> Target version (default: this CLI's version)
147
+ --allow-dirty Run with uncommitted changes
148
+ --force Allow downgrading
149
+
150
+ OPTIONS — app
151
+ --type=<type> App type: angular | ionic | flutter (required)
152
+ --name=<name> Application name (required)
153
+ --tags=<tags> Comma-separated Nx tags
154
+ --cspConnectSrc=<url> Angular only — pre-fill CSP connect-src in csp-allowlist.json
155
+ --dir=<path> Put the app in apps/<path>/<name> (v0.17.0+)
156
+ --port=<n> Dev-server port (default: the lowest free port from 4200; v0.35.0+)
157
+ --env-layout=<layout> Angular/Ionic — default | per-env (v0.35.0+)
158
+
159
+ OPTIONS — shared (--app or --all required; v0.35.0+)
160
+ --app=<a,b> Angular/Ionic apps to wire the shared assets and styles into
161
+ --all Every Angular/Ionic app
162
+
163
+ OPTIONS — env
164
+ --name=<name> Environment slug, e.g. qa, sit, staging (required)
165
+ --app=<a,b> | --all Apps to add it to (one of them is required)
166
+ --from=<env> Environment to copy (default uat); secret values become
167
+ ${APP_ENV_KEY} placeholders filled at build time
168
+ --api-url=<url> API base URL of the new environment
169
+ --production[=false] production flag of the new Angular env file (default: as --from)
170
+ --base-href=<path> Base href of the new configuration (default: as --from)
171
+ --domains=<hosts> aes-gcm domain lock of the new release configuration
172
+
173
+ OPTIONS — migrate
174
+ --source=<path> Project to migrate: its repo root (required; read only)
175
+ --name=<name> App name, kebab-case (default: the Angular project name or
176
+ the pubspec name); for workspace sources the report name
177
+ --adapter=<id> Skip detection: angular-cli | flutter | nx-workspace | angular-workspace | ionic |
178
+ npm-workspaces, or an adapter listed in nx.json
179
+ --min-confidence=<n> Use the best adapter when it reaches n (0.50 to 1.00; default 0.80; v0.15.0+)
180
+ --dir=<path> Single-app sources: put the app in apps/<path>/<name> (v0.16.0+)
181
+ --detect Print the detection table (adapter, confidence, reasons) and
182
+ exit; writes nothing, works outside a workspace
183
+ --projects=<a,b> Workspace sources: projects to migrate (default: every supported one)
184
+ --no-deps Workspace sources: only the --projects named, not the libs they import
185
+ --prefix=<p> Workspace sources: rename projects to <p>-<name> (aliases kept)
186
+ --force-angular Migrate even when the workspace and the source use different
187
+ Angular majors (the report flags it)
188
+ --max-files=<n> Fail when more than n files would be copied (default: 20000)
189
+ --no-rewrite-imports Keep the copied imports as they were (v0.21.0+). By default,
190
+ relative imports into another moved project, imports through the
191
+ source baseUrl, @nrwl/* packages and relative SCSS paths are
192
+ rewritten in the copies; the report lists each one
193
+ --rollback=<name> Undo migration <name> (v0.13.0+): removes the files it created and
194
+ reverts its package.json/tsconfig/nx.json changes; anything edited
195
+ since is kept and listed in docs/migrations/<name>.rollback.md
196
+ --force With --rollback: remove or restore the edited items too
197
+ --config=<file> Run the migrations listed in a JSON batch file (v0.14.0+), all or
198
+ nothing: { "defaults": {...}, "migrations": [ { "source": ... } ] };
199
+ relative sources are resolved from the file's folder
200
+ Writes docs/migrations/<name>.md and <name>.manifest.json (for --rollback). Without
201
+ --adapter the most confident adapter is used if its confidence is at least 0.80.
202
+
203
+ OPTIONS — infra
204
+ --with=<parts> docs | ci | quality | upgrades, comma-separated, or all | none
205
+ (default: all)
206
+ --ci=<providers> github-actions | jenkins, comma-separated (default: github-actions);
207
+ the upgrade workflow is GitHub Actions only
208
+ --ci-cache GitHub Actions: cache the Nx cache directory between runs
209
+ --flutter=<mode> Set up Flutter in CI: auto (when a pubspec.yaml is under apps/ or
210
+ libs/) | on | off; default auto
211
+ --upgrade-schedule=<when> weekly (Monday 03:17 UTC) | monthly (1st, 03:17 UTC); default weekly
212
+ --upgrade-scope=<scope> polystack (pstack update) | nx-minor (also nx migrate within the
213
+ current Nx major); default polystack
214
+ --lint-staged=warn|block ESLint on commit: report only (warn) or block on errors (v0.36.0+)
215
+ --force Overwrite files that already exist (.husky/pre-push is always
216
+ appended to, never replaced)
217
+ Existing files are kept and listed; npm scripts and dependencies are only added when missing.
218
+
219
+ GLOBAL FLAGS
220
+ --dry-run, -d Preview changes without writing files
221
+ --verbose Verbose output
222
+ --help, -h Show this help
223
+ --version, -v Print version
224
+
225
+ Flag values must use --flag=value (a space-separated value is read as an argument).
226
+ ```
227
+
228
+ **Version delegation.** Run inside a workspace that has `@mouryaamit/nx-polystack` in `node_modules`,
229
+ the global `pstack` hands `app`, `env`, `preset`, `migrate` and `infra` to that workspace's copy. `app`, `env`,
230
+ `migrate` and `infra` run from the workspace root (a relative `migrate --source` is made absolute first); `preset`
231
+ and any other command run from the current directory. `pstack migrate` needs nx-polystack 0.12.0 or newer (0.13.0 for `--rollback`, 0.14.0 for `--config`, 0.15.0 for `--min-confidence`, 0.16.0 for `--dir`) pinned
232
+ in the workspace, `pstack infra` 0.9.0 or newer. If the workspace
233
+ copy is older than the global CLI you get a one-line hint to run `pstack update`. `new`, `update`, and `help` /
234
+ `--help` / `--version` always run from the global CLI.
235
+
236
+ ---
237
+
238
+ ## 3a. pstack new — create a workspace
239
+
240
+ ```bash
241
+ pstack new <dir> [--npmScope=<scope>] [--baseBranch=<branch>] [--infra=…] [--ci=…] [--llm=…]
242
+ [--projectDescription=…] [--skip-install] [--skip-git] [--force] [--dry-run]
243
+ ```
244
+
245
+ 1. Refuses a non-empty `<dir>`, and a `<dir>` inside another Nx workspace unless `--force`.
246
+ 2. `--baseBranch` must match `/^[\w./-]+$/` (letters, digits, `_`, `.`, `/`, `-`).
247
+ 3. Generates the same files as `pstack preset`, plus `@mouryaamit/nx-polystack` pinned to the CLI's version.
248
+ That includes the `pstack infra` files (§3c), all four parts by default; `--infra=none` skips them and
249
+ `--infra=docs,ci` (any subset) picks parts. `--ci` (default `github-actions`), `--ci-cache`, `--flutter`,
250
+ `--upgrade-schedule` and `--upgrade-scope` are passed to it.
251
+ 4. Runs `git init -b <baseBranch>`, then `npm install`, then `git add -A` and
252
+ `git commit --no-verify -m "chore: initial polystack workspace"`. `git init` comes first because the generated
253
+ `prepare` script runs husky, which needs `.git`; `--no-verify` skips the hooks for that first commit.
254
+ Later commits run the pre-commit hook: `npx lint-staged`, configured in `package.json` (Prettier on
255
+ changed `ts/html/scss/json/md` files, `eslint --fix` on `ts`). Workspaces created before v0.18.1 had
256
+ no lint-staged config, so their commits failed; the 0.18.1 migration `add-lint-staged-config` adds it
257
+ (`pstack update`).
258
+ 5. If git is missing or a git step fails, `pstack new` warns and continues without git. If `npm install` fails the
259
+ files stay in place; fix the error and re-run `npm install` there.
260
+
261
+ ---
262
+
263
+ ## 3b. pstack update — upgrade a workspace
264
+
265
+ ```bash
266
+ pstack update [--to=<version>] [--dry-run] [--allow-dirty] [--force]
267
+ ```
268
+
269
+ 1. Reads the pinned version of `@mouryaamit/nx-polystack` from `package.json` (`1.2.0`, or the installed
270
+ version for a range such as `^1.2.0`).
271
+ 2. Target is `--to`, else the global CLI's version. Downgrades need `--force`. If the global CLI is older than the
272
+ workspace pin, `update` tells you to upgrade the global CLI first (or pass `--force`).
273
+ 3. Needs a clean git tree unless `--allow-dirty`. The check covers only the workspace folder.
274
+ 4. Installs with `npm install @mouryaamit/nx-polystack@<to> --save-dev --save-exact` (`--save-prod` if the plugin
275
+ is under `dependencies`), so npm rewrites `package.json` itself.
276
+ 5. If the install fails, or the installed version is not the one requested, `package.json` and
277
+ `package-lock.json` are restored (a lockfile created by the failed install is deleted).
278
+ 6. Runs every plugin migration newer than the old version and up to the new one, using the new version's code.
279
+
280
+ A failed migration stops the run; earlier ones stay applied. Review with `git diff`. `--verbose` is passed
281
+ through to the migration step.
282
+
283
+ `--dry-run` prints the planned change and exits before the dirty-tree check, so it works in a dirty tree.
284
+
285
+ **If migrations fail.** By then the plugin is already on the new version. `update` prints how to retry:
286
+ either `git checkout -- . && npm install` and then `pstack update` again, or, after fixing the cause, rerun only
287
+ the migrations with `npx pstack _migrate --from=<from> --to=<to>`.
288
+
289
+ **The 0.4.1 migration.** `add-lint-dependencies` adds the ESLint packages the root `.eslintrc.json` needs
290
+ (`eslint`, `@nx/eslint`, `@nx/eslint-plugin`, `@typescript-eslint/*`, `eslint-config-prettier`) when missing, and,
291
+ for Angular 15 workspaces, any missing build/lint package (`@angular-devkit/build-angular`, `@angular/compiler-cli`,
292
+ `@angular/cli`, `@nx/angular`, `@angular-eslint/*`) at the installed Angular version. It never changes an existing
293
+ version and never adds runtime packages. New workspaces from `pstack new` pin `nx` and `@nx/*` to `~17.0.6`.
294
+
295
+ **The 0.4.0 migration.** `angular-release-target` rewrites Angular apps generated by v0.3.x so `nx build <app>`
296
+ works and the hardened pipeline moves to `nx run <app>:release:<config>`. See "Upgrading from v0.3.x" in section 5.
297
+
298
+ **The 0.3.0 migration.** v0.3.0 makes `sharp` and `crypto-js` optional peers, so npm may stop installing them
299
+ automatically. The `add-executor-peers` migration adds `sharp@^0.33.0` and/or `crypto-js@^4.2.0` to
300
+ `devDependencies` when neither `dependencies` nor `devDependencies` already lists them.
301
+
302
+ ---
303
+
304
+ ## 3c. pstack infra — repo docs, CI gates, quality checks
305
+
306
+ ```bash
307
+ pstack infra [--with=docs,ci,quality,upgrades] [--ci=github-actions,jenkins] [--ci-cache] [--flutter=auto|on|off]
308
+ [--upgrade-schedule=weekly|monthly] [--upgrade-scope=polystack|nx-minor] [--force] [--dry-run]
309
+ npx nx g @mouryaamit/nx-polystack:infra [same options]
310
+ ```
311
+
312
+ Adds the repo files and checks a team needs before the first pull request. `pstack new` (and
313
+ `:preset`) run it with every part by default; `--infra=none` or a subset (`--infra=docs,ci`) changes
314
+ that, and `--ci`, `--ci-cache`, `--flutter`, `--upgrade-schedule` and `--upgrade-scope` are passed through.
315
+
316
+ | Part | Files | package.json (only when missing) |
317
+ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
318
+ | `docs` | `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` (Contributor Covenant 2.1 by link), `SECURITY.md`, `.github/PULL_REQUEST_TEMPLATE.md`, `.github/ISSUE_TEMPLATE/{bug,feature,config}.yml` | — |
319
+ | `ci` | GitHub: `.github/workflows/ci.yml`, `.github/workflows/pr-title.yml`; Jenkins: `Jenkinsfile`; both: `tools/scripts/check-cycles.js`, `tools/config/allowed-cycles.json` | `check:cycles`; GitHub: `@commitlint/cli` + `config-conventional` and `commitlint.config.js` if no commitlint config |
320
+ | `quality` | `knip.json`, `.secretlintrc.json`, `.secretlintignore`, `.husky/pre-push` | `stale-code`, `check:prepush`, `check:audit`; `knip`, `secretlint`, its recommended preset, `husky` (+ `prepare`) |
321
+ | `upgrades` | `.github/workflows/dependency-upgrade.yml` (GitHub Actions only) | — |
322
+
323
+ - **Never overwrites.** A file that exists is kept and listed at the end ("pass --force to
324
+ overwrite"); `--force` replaces it. `.husky/pre-push` is never replaced: the check is appended once,
325
+ after a `# nx-polystack:infra pre-push` marker line. npm scripts and dependencies are only added
326
+ when missing; a script that exists with another command is kept and listed. A second run changes
327
+ nothing.
328
+ - **Placeholders.** `<conduct-contact>` and `<security-contact>` are written as-is and listed under
329
+ "Fill in".
330
+ - **`ci.yml`** runs on pull requests and on pushes to the base branch (nx.json
331
+ `affected.defaultBase`, else `master`): checkout with full history, setup-node from `.nvmrc`,
332
+ `npm ci`, `nrwl/nx-set-shas` (`main-branch-name` = the base branch),
333
+ `npx nx affected -t lint typecheck test build --parallel=3`, `npm run check:cycles`. `--ci-cache` adds an
334
+ `actions/cache` step for the Nx cache (`.nx/cache`, or nx.json `cacheDirectory`).
335
+ - **Flutter.** `--flutter=auto|on|off` (default `auto`). With `auto`, when a `pubspec.yaml` exists
336
+ under `apps/` or `libs/`, `ci.yml` gets a `subosito/flutter-action@v2` step (`channel: stable`,
337
+ `cache: true`) after setup-node, and the `Jenkinsfile` runs `flutter --version` first in Install
338
+ (Flutter must be on the agent's PATH). A new workspace has no Flutter project yet: after
339
+ `pstack app --type=flutter`, run `pstack infra --with=ci --force` to add the step.
340
+ - **`pr-title.yml`** checks the pull request title with the workspace's own commitlint
341
+ (`echo "$TITLE" | npx --no-install commitlint`); no third-party action.
342
+ - **`Jenkinsfile`**: install, affected lint/test/build (base: `origin/$CHANGE_TARGET` for pull
343
+ requests, `HEAD~1` on the base branch, else `origin/<base>`), cycles.
344
+ - **Cycle gate.** `npm run check:cycles` reads the project graph (`nx graph --file=<tmp>.json`),
345
+ finds cycles (strongly connected groups, plus self-dependencies; `npm:` packages ignored) and fails
346
+ only on cycles not listed in `tools/config/allowed-cycles.json` (`[["app-a","lib-b"]]`, any order).
347
+ It is plain Node with no dependencies; `--graph=<file>` reads a saved graph instead.
348
+ - **Stale code.** `npm run stale-code` runs `knip --no-exit-code`: a report, never a failure.
349
+ `knip.json` lists the entry and project globs, the plugin under `ignoreDependencies`, and
350
+ `flutter`/`dart` under `ignoreBinaries` only when the workspace has Flutter. `pstack lib
351
+ --type=design-tokens` adds its `generated/**` and `src/lib/tokens.ts` outputs to the `ignore`
352
+ list of an existing `knip.json`. A `knip.json` written by v0.9.0 still has `**/dist/**`,
353
+ `libs/**/generated/**`, `crypto-js`/`sharp` and `dart` entries; knip prints them under
354
+ "Configuration hints" when they match nothing. The hints are harmless; delete those entries to
355
+ silence them.
356
+ - **Pre-push.** `npm run check:prepush` runs `secretlint "**/*"` first (node_modules, dist, .nx and
357
+ the lockfile are ignored), which blocks the push on a finding, then
358
+ `npm audit --omit=dev --audit-level=high` as a warning only, and ends with a line pointing to
359
+ `npm run check:audit`, the strict audit that fails on high or critical advisories. (Advisories
360
+ with no fix for the workspace's framework major would otherwise block every push.) The 0.9.1
361
+ migration `prepush-audit-warn-only` rewrites a `check:prepush` that is exactly the v0.9.0 default
362
+ and adds `check:audit` when missing.
363
+ - **Upgrade workflow.** Weekly (Monday 03:17 UTC) or `--upgrade-schedule=monthly` (the 1st, 03:17
364
+ UTC), plus a manual run. `polystack` scope: `pstack update --to=<latest release>`; `nx-minor` also
365
+ runs `nx migrate nx@<current major>`, `npm install` and the Nx migrations. Opens or updates the
366
+ `chore/dependency-upgrade` pull request (`chore(deps): scheduled dependency upgrade`) with
367
+ `peter-evans/create-pull-request@v6`, and `subosito/flutter-action@v2` when Flutter is set up. With only `--ci=jenkins` it is skipped, with a note.
368
+
369
+ - **Settings.** The upgrade workflow finds the latest version with `npm view` and needs "Allow GitHub
370
+ Actions to create and approve pull requests" in the repo settings.
371
+
372
+ - Actions are pinned to major tags: `actions/checkout@v4`, `actions/setup-node@v4`,
373
+ `nrwl/nx-set-shas@v4`, `actions/cache@v4`, `peter-evans/create-pull-request@v6`.
374
+
375
+ The llm block is refreshed and lists the new npm scripts. Through the global CLI, `pstack infra`
376
+ needs nx-polystack 0.9.0 or newer pinned in the workspace.
377
+
378
+ ```bash
379
+ pstack infra # all parts, GitHub Actions
380
+ pstack infra --with=docs,ci --ci=jenkins # docs and a Jenkinsfile
381
+ pstack infra --with=upgrades --upgrade-schedule=monthly --upgrade-scope=nx-minor
382
+ pstack infra --with=docs --dry-run # preview
383
+ pstack infra --force # overwrite existing files with the templates
384
+ ```
385
+
386
+ ---
387
+
388
+ ## 4. pstack preset — bootstrap a workspace
389
+
390
+ Creates the complete Nx workspace root skeleton in the **current directory**. Run this in a
391
+ freshly created, empty directory.
392
+
393
+ ```bash
394
+ pstack preset [options]
395
+ ```
396
+
397
+ ### Options
398
+
399
+ | Option | Default | Description |
400
+ | ----------------------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
401
+ | `--npmScope=<scope>` | `mouryaamit` | npm scope written into `nx.json` and `tsconfig.base.json` path aliases |
402
+ | `--baseBranch=<branch>` | `master` | Default git branch (`defaultBase` in `nx.json`) |
403
+ | `--infra=<parts>` | `all` | Runs `:infra` (§3c) with these parts: `docs`, `ci`, `quality`, `upgrades`; or `all`, `none`. |
404
+ | `--ci=<providers>` | `github-actions` | CI for the `:infra` ci part. Values: `github-actions`, `jenkins`. Comma-separated for multiple. |
405
+ | `--llm=<tools>` | — | Runs `:llm` for these providers: `claude`, `agents`, `copilot` (`codex`, `openai-gpt` → `agents`). |
406
+ | `--projectDescription=<text>` | — | Short project description written into `package.json` |
407
+ | `--skipFormat` | false | Skip the Prettier format pass after generation |
408
+ | `--skipInstall` | false | No-op for `preset` (it never installs); kept for compatibility |
409
+
410
+ ### What is generated
411
+
412
+ **Always generated (workspace root skeleton):**
413
+
414
+ ```
415
+ nx.json
416
+ tsconfig.base.json
417
+ package.json
418
+ .nvmrc Node 20
419
+ .npmrc legacy-peer-deps=true
420
+ .editorconfig
421
+ .gitattributes
422
+ .gitignore
423
+ .prettierrc
424
+ .prettierignore
425
+ .eslintrc.json
426
+ .eslintignore
427
+ commitlint.config.js
428
+ .husky/
429
+ pre-commit
430
+ commit-msg
431
+ tools/config/
432
+ sri-cdn-allowlist.json
433
+ (nx.json also gets pstack.envEncryption — see "Env encryption settings (v0.25.0)")
434
+ ```
435
+
436
+ **Repo infrastructure (`--infra`, default all parts; written by `:infra`, see §3c):** repo docs,
437
+ CI (`--ci=github-actions`: `.github/workflows/ci.yml` and `pr-title.yml`; `--ci=jenkins`: `Jenkinsfile`;
438
+ both: the dependency-cycle check), quality checks (knip, pre-push audit + secretlint) and, with GitHub
439
+ Actions, `.github/workflows/dependency-upgrade.yml`. The old `.github/workflows/build.yml` template is gone.
440
+
441
+ **Conditional — AI-assistant instructions (`--llm`, written by `:llm` after formatting):**
442
+
443
+ | Flag value | File |
444
+ | ---------------------- | --------------------------------- |
445
+ | `claude` | `CLAUDE.md` |
446
+ | `agents` | `AGENTS.md` |
447
+ | `codex` / `openai-gpt` | `AGENTS.md` (aliases of `agents`) |
448
+ | `copilot` | `.github/copilot-instructions.md` |
449
+
450
+ Unknown values fail with the supported list. `.codex/instructions.md` is no longer generated.
451
+ See `:llm` in §6 for the block these files get.
452
+
453
+ ### Examples
454
+
455
+ ```bash
456
+ # Minimal workspace
457
+ mkdir my-workspace && cd my-workspace
458
+ pstack preset --npmScope=acme
459
+
460
+ # Full setup — GitHub Actions CI + Claude AI config
461
+ pstack preset --npmScope=acme --ci=github-actions --llm=claude
462
+
463
+ # Jenkins CI + Claude + Copilot
464
+ pstack preset --npmScope=acme --ci=jenkins --llm=claude,copilot
465
+
466
+ # Skeleton only, no repo docs / CI / checks
467
+ pstack preset --npmScope=acme --infra=none
468
+
469
+ # Preview without writing
470
+ pstack preset --npmScope=acme --dry-run
471
+ ```
472
+
473
+ ---
474
+
475
+ ## 5. pstack app — scaffold an application
476
+
477
+ Adds a new application to an **existing Nx workspace**. Must be run from the workspace root
478
+ (where `nx.json` exists). If no `nx.json` is found, the command exits with an error.
479
+
480
+ ```bash
481
+ pstack app --type=<type> --name=<name> [options]
482
+ ```
483
+
484
+ ### Options
485
+
486
+ | Option | Required | Description |
487
+ | ----------------------- | -------- | -------------------------------------------------------------------------- |
488
+ | `--type=<type>` | Yes | Application type: `angular`, `ionic` or `flutter` |
489
+ | `--name=<name>` | Yes | Application name — becomes `apps/<name>/` (or `apps/<dir>/<name>/`) |
490
+ | `--dir=<path>` | — | Put the app in `apps/<path>/<name>` (v0.17.0+, rules below) |
491
+ | `--tags=<tags>` | — | Comma-separated Nx tags (e.g. `platform:web,scope:app`) |
492
+ | `--cspConnectSrc=<url>` | — | Angular/Ionic — pre-fills the `connect-src` entry in `csp-allowlist.json` |
493
+ | `--appId=<id>` | — | Ionic only — Capacitor appId (default `com.example.<name without dashes>`) |
494
+
495
+ `--dir` takes kebab-case folders separated by `/` (at most three; not `dist`, `tmp`, `coverage` or
496
+ `out-tsc`; not through another project). Relative paths and build output (`dist/apps/<dir>/<name>`)
497
+ follow the folder; the project name, npm scripts, `environments/<name>/` and the
498
+ `@mouryaamit/<name>` alias stay keyed by name. A name another project already uses is refused, with
499
+ or without `--dir`. Needs nx-polystack 0.17.0 in the workspace and a 0.17.0 global CLI.
500
+
501
+ ### What is generated — Angular (`--type=angular`)
502
+
503
+ ```
504
+ apps/<name>/
505
+ project.json Nx targets: build, serve, release, lint, extract-i18n
506
+ tsconfig.json
507
+ tsconfig.app.json
508
+ tsconfig.spec.json
509
+ .eslintrc.json
510
+ csp-allowlist.json CSP overrides (per-app)
511
+ src/
512
+ index.html
513
+ main.ts platformBrowserDynamic().bootstrapModule(AppModule)
514
+ styles.scss
515
+ .htaccess Apache SPA routing, CSP with a per-request nonce, security headers (pstack csp)
516
+ app/
517
+ app.module.ts BrowserModule + HttpClientModule
518
+ app.component.ts OnPush change detection
519
+ app.component.html
520
+ app.component.scss
521
+ app-routing.module.ts Empty routes array
522
+ server/
523
+ nginx.conf Nginx try_files + security headers
524
+ README.md Deployment notes
525
+
526
+ environments/<name>/
527
+ environment.ts
528
+ environment.uat.ts
529
+ environment.prod.ts
530
+ ```
531
+
532
+ **Also adds:**
533
+
534
+ - 6 npm scripts to root `package.json` (see the table below)
535
+ - `tsconfig.base.json` path alias: `@mouryaamit/<name>` → `apps/<name>/src`
536
+ - Nx tags: `scope:app`, `type:app`, `platform:web`
537
+
538
+ **Targets in `project.json`:**
539
+
540
+ | Target | Executor | What it does |
541
+ | ---------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
542
+ | `build` | `@angular-devkit/build-angular:browser` | Plain Angular build to `dist/apps/<name>`. Configurations `production` (default), `uat`, `development`; `production` and `uat` swap `environments/<name>/environment.ts` for the `.prod.ts` / `.uat.ts` file. Assets include `src/.htaccess`. |
543
+ | `serve` | `@angular-devkit/build-angular:dev-server` | Dev server; configurations `production` / `uat` / `development` point at the matching `build` configuration. Default `development`. |
544
+ | `release` | `@mouryaamit/nx-polystack:build` | Hardened pipeline that wraps `build` (`buildTarget: <name>:build`): env encryption, EXIF stripping, build meta, optional CSP nonce / SRI, and non-DEV release hardening (leak check, source maps, comments, console, obfuscation). Configurations `dev`, `uat`, `prod`; default `dev`. |
545
+ | `lint`, `extract-i18n` | `@nx/eslint:lint`, Angular extract-i18n | Unchanged. |
546
+
547
+ `nx build <name>` is a plain Angular build. Use `nx run <name>:release:prod` for the hardened build.
548
+
549
+ **npm scripts:**
550
+
551
+ | Script | Command |
552
+ | ------------------------------ | ------------------------------------------- |
553
+ | `serve:<name>` | `nx serve <name>` |
554
+ | `build:<name>:dev` | `nx run <name>:release:dev` |
555
+ | `build:<name>:uat` | `nx run <name>:release:uat` |
556
+ | `build:<name>:prod` | `nx run <name>:release:prod` |
557
+ | `build:<name>:prod:secure` | `nx run <name>:release:prod --secure` |
558
+ | `build:<name>:prod:secure:sri` | `nx run <name>:release:prod --secure --sri` |
559
+
560
+ **Angular version.** Generated apps target Angular 15. Packages are only ever added, never upgraded:
561
+
562
+ - No `@angular/core` in the workspace → the Angular 15 set (`~15.2.0`, TypeScript `~4.9.5`) plus the lint packages
563
+ (`@nx/angular`, `@nx/eslint` at the workspace's Nx version, `@angular-eslint/*` `~15.2.0`) is added.
564
+ - Angular 15 already installed → missing build and lint packages are added at your installed Angular version
565
+ (`@angular-devkit/build-angular`, `@angular/compiler-cli`, `@angular/cli`, `@nx/angular`, `@nx/eslint`,
566
+ `@angular-eslint/*`), plus the runtime packages the generated code imports (`@angular/common`, `compiler`,
567
+ `platform-browser`, `platform-browser-dynamic`, `router`, `rxjs`, `tslib`, `zone.js`). Existing versions are kept.
568
+ - Another Angular major → nothing is added; `pstack app` prints which packages to install at versions matching
569
+ your Angular. Angular 16–17 likely work with the generated files.
570
+
571
+ **Upgrading from v0.3.x.** Apps generated by older versions have a `build` target that runs the plugin executor and
572
+ cannot build. `pstack update` runs the `angular-release-target` migration, which moves that target to `release`,
573
+ gives `build` the Angular builder, renames `serve` configurations, and rewrites matching npm scripts to
574
+ `nx run <app>:release:<config>`. Details:
575
+
576
+ - Custom configurations (e.g. `qa`) are carried over to `build` and `release`.
577
+ - Only `nx run <app>:build:<config>` commands are rewritten in scripts (matched on word boundaries; a trailing `--` is dropped).
578
+ - Ionic and other non-Angular apps, and apps that already have a `release` target, are skipped (the latter with a warning).
579
+ - Re-running is a no-op.
580
+
581
+ ### What is generated — Ionic (`--type=ionic`)
582
+
583
+ An Angular app (everything in the Angular section above) turned into an Ionic 7 + Capacitor 5 app:
584
+
585
+ - `src/app/app.module.ts` imports `IonicModule.forRoot()` and uses `IonicRouteStrategy`; `app.component.html` is
586
+ `<ion-app><ion-router-outlet>`; `index.html` has a mobile viewport (`viewport-fit=cover`); `styles.scss` imports the
587
+ Ionic core CSS; ionicons SVGs are copied to `/svg` by the build.
588
+ - `capacitor.config.ts` — `appId` (`--appId`), `appName`, `webDir: '../../dist/apps/<name>'`.
589
+ - `package.json` in the app folder — its own `@capacitor/core`, `android`, `ios` and `cli` (`~5.7.0`), kept out of
590
+ the root install; plus a `.gitignore` for its `node_modules` and native build output.
591
+ - `project.json`: `build` / `serve` / `release` as for Angular (`release.options.type: ionic`), and
592
+ `cap-sync`, `cap-open`, `cap-add` (executor `:capacitor`, platform given as `--platform=android|ios`).
593
+ - Root `package.json`: Angular 15 packages as for Angular apps, plus `@ionic/angular ~7.8.0` when missing.
594
+ `pstack app` then installs the root packages and the app's own package.json.
595
+
596
+ | Script | Command |
597
+ | ------------------------------------- | -------------------------------------------------------------------- |
598
+ | `build:<name>:<dev\|uat\|prod>` | `nx run <name>:release:<env>` |
599
+ | `build:<name>:<env>:android` / `:ios` | release build, then `nx run <name>:cap-sync --platform=android\|ios` |
600
+ | `open:<name>:android` / `:ios` | `nx run <name>:cap-open --platform=android\|ios` |
601
+
602
+ First native build:
603
+
604
+ ```bash
605
+ pstack app --type=ionic --name=field-ops --appId=com.acme.fieldops
606
+ npx nx run field-ops:release:prod
607
+ npx nx run field-ops:cap-add --platform=android # once — creates apps/field-ops/android
608
+ npm run build:field-ops:prod:android # release build + cap sync
609
+ npm run open:field-ops:android # opens Android Studio
610
+ ```
611
+
612
+ `pstack env --name=qa --app=<name>` adds `qa` to `build`, `serve` and `release`, plus `build:<name>:qa:android` / `:ios`.
613
+
614
+ Native prerequisites (Capacitor 5): Node 16+, JDK 17 and Android Studio Flamingo or newer for Android; Xcode 14.1+ and
615
+ CocoaPods for iOS (macOS only). On Linux, set `CAPACITOR_ANDROID_STUDIO_PATH` for `cap-open`.
616
+
617
+ ### What is generated — Flutter (`--type=flutter`)
618
+
619
+ ```
620
+ apps/<name>/
621
+ project.json Nx targets: flutter-build (3 configs), serve
622
+ pubspec.yaml
623
+ analysis_options.yaml
624
+ .gitignore
625
+ lib/
626
+ main.dart
627
+ web/
628
+ index.html loads flutter_bootstrap.js (no inline script); keeps $FLUTTER_BASE_HREF
629
+ manifest.json
630
+ server/
631
+ nginx.conf
632
+
633
+ environments/<name>/
634
+ env.dev.json
635
+ env.uat.json
636
+ env.prod.json
637
+ ```
638
+
639
+ Web builds (`build-web`, `serve`) need Flutter 3.22 or later. Add icons under `web/` if you want them.
640
+
641
+ ### Examples
642
+
643
+ ```bash
644
+ # Angular SPA
645
+ pstack app --type=angular --name=portal
646
+
647
+ # Angular with tags and CSP entry
648
+ pstack app --type=angular --name=admin --tags=platform:web,scope:app --cspConnectSrc=https://api.example.com
649
+
650
+ # Flutter
651
+ pstack app --type=flutter --name=mobile --tags=platform:mobile
652
+
653
+ # Preview — no files written
654
+ pstack app --type=angular --name=portal --dry-run
655
+ ```
656
+
657
+ ---
658
+
659
+ ## 6. Nx plugin usage — generators
660
+
661
+ When the plugin is installed as a dev dependency in an Nx workspace, generators can also be invoked
662
+ through Nx directly:
663
+
664
+ ```bash
665
+ npx nx g @mouryaamit/nx-polystack:preset [options]
666
+ npx nx g @mouryaamit/nx-polystack:app --type=angular --name=portal [options]
667
+
668
+ # Preview without writing
669
+ npx nx g @mouryaamit/nx-polystack:app --type=angular --name=portal --dry-run
670
+ ```
671
+
672
+ All options are identical to the `pstack` CLI flags. The `--dry-run` flag is supported by both Nx and
673
+ the `pstack` CLI.
674
+
675
+ ### `:preset` generator schema
676
+
677
+ ```jsonc
678
+ {
679
+ "npmScope": "mouryaamit", // string — default: "mouryaamit"
680
+ "baseBranch": "master", // string — default: "master"
681
+ "apps": "angular,flutter", // string — comma-separated app types (stored in nx.json)
682
+ "infra": "all", // string — :infra parts: docs,ci,quality,upgrades | all | none
683
+ "ci": "github-actions", // string — comma-separated CI providers (default: github-actions)
684
+ "ciCache": false, // boolean — passed to :infra
685
+ "flutter": "auto", // "auto" | "on" | "off" — passed to :infra
686
+ "upgradeSchedule": "weekly", // "weekly" | "monthly" — passed to :infra
687
+ "upgradeScope": "polystack", // "polystack" | "nx-minor" — passed to :infra
688
+ "llm": "claude,copilot", // string — comma-separated :llm providers
689
+ "projectDescription": "...", // string
690
+ "skipFormat": false, // boolean
691
+ "skipInstall": false // boolean
692
+ }
693
+ ```
694
+
695
+ ### `:llm` generator / `pstack llm` (v0.7.0)
696
+
697
+ ```bash
698
+ pstack llm [--providers=claude,agents,copilot] [--dry-run]
699
+ npx nx g @mouryaamit/nx-polystack:llm --providers=claude,agents,copilot
700
+ ```
701
+
702
+ Writes a generated description of the workspace — npm scope, Nx / Angular / plugin versions, an apps
703
+ table (type detected from targets), environments, a libs table with import aliases, common commands
704
+ and rules — between `<!-- nx-polystack:start -->` and `<!-- nx-polystack:end -->` in `CLAUDE.md`
705
+ (`claude`), `AGENTS.md` (`agents`; `codex` and `openai-gpt` are aliases) and
706
+ `.github/copilot-instructions.md` (`copilot`). Default: all three.
707
+
708
+ A missing file is created with a title; a file with markers gets only the block replaced; a file
709
+ without markers gets the block appended; malformed markers stop the run with an error naming the
710
+ file. Text outside the block is never changed. `:app`, `:lib` and `:env` refresh the block in files
711
+ that already contain the markers. Through the global CLI, `pstack llm` needs nx-polystack 0.7.0 or
712
+ newer pinned in the workspace.
713
+
714
+ ### `:migrate` generator / `pstack migrate` (v0.8.0, Nx import v0.10.0)
715
+
716
+ ```bash
717
+ pstack migrate --source=<path> [--name=<app>] [--adapter=angular-cli|flutter|nx-workspace|angular-workspace|ionic] [--detect] [--dry-run] [--force-angular]
718
+ [--projects=<a,b>] [--no-deps] [--prefix=<p>]
719
+ npx nx g @mouryaamit/nx-polystack:migrate --source=<path> [same options]
720
+ ```
721
+
722
+ Copies an existing standalone project into the workspace as `apps/<name>`, in the shape `pstack app`
723
+ produces. The source is only read; git history is not carried over.
724
+
725
+ - **Detection.** `angular-cli`: `angular.json` with exactly one application project, `@angular/core`,
726
+ the build `main` file. `flutter`: `pubspec.yaml` with the Flutter SDK, `lib/main.dart`. `nx.json`
727
+ disqualifies both; more than one Angular application project disqualifies `angular-cli`; an Ionic
728
+ app scores below the threshold. The best adapter is used at confidence ≥ 0.80; otherwise the
729
+ command stops with the table and suggests `--adapter`. `--detect` only prints the table.
730
+ - **Angular CLI apps.** Files copied without `node_modules`, `dist`, `.angular`, `.git`, IDE folders,
731
+ `coverage` and the workspace-level files. `project.json` is built from `angular.json`: every
732
+ target, every path option moved under `apps/<name>`, `dist/<x>` → `dist/apps/<name>`, target
733
+ references renamed, plus a polystack `release` target (`production` → `prod`, `development` →
734
+ `dev`, other configurations keep their name) and an `@nx/eslint:lint` target if missing. The
735
+ tsconfigs extend `tsconfig.base.json` (source `paths` merged in, clashes reported); the ESLint
736
+ config extends the root one (or the polystack one is generated). Source dependencies are added only
737
+ when missing (clashes reported); a different Angular major in the workspace stops the command
738
+ unless `--force-angular`. `serve:<name>` / `build:<name>:<env>` npm scripts are added; source
739
+ scripts are listed in the report. Environment files stay where they were.
740
+ - **Flutter apps.** Files are copied without `build`, `.dart_tool`, Pods, Gradle caches, generated
741
+ plugin lists and `flutter/ephemeral` folders. The app gets the `pstack app --type=flutter` targets
742
+ and npm scripts, without the FlutterFlow export. Missing `env/dev|uat|prod.json` files are created
743
+ as `{}`. The report notes pubspec path dependencies outside the source repo, product flavors and
744
+ extra `lib/main_*.dart` entrypoints.
745
+ - **Both.** In a git work tree only the files git lists are copied. Possible secrets (`.env*`,
746
+ keystores, `*.pem`, `key.properties`, Firebase configs, `.npmrc`) are never copied, and the report
747
+ lists them. File modes are kept. `--max-files` (default 20000) caps the copy. Angular 17+
748
+ application-builder sources are converted to Angular 15 builders (see Angular 17+ sources).
749
+ - **Report.** `docs/migrations/<name>.md`: adapter and confidence, copied/skipped counts and the
750
+ skipped paths, dependency and alias clashes, source scripts, Angular notes, and a next-steps
751
+ checklist. The llm block is refreshed.
752
+ - **Undo.** `pstack migrate --rollback=<name>` undoes a migration made with v0.13.0+ from
753
+ `docs/migrations/<name>.manifest.json`; what was edited since is kept and listed (`--force`
754
+ overrides, `--dry-run` previews). See the user manual §6.5.
755
+ - **Batches.** `pstack migrate --config=<file>` runs the migrations listed in a JSON file, all or
756
+ nothing; each entry gets its own report and manifest. See the user manual §6.5.
757
+
758
+ ```bash
759
+ pstack migrate --source=../legacy-portal --detect
760
+ pstack migrate --source=../legacy-portal --name=portal
761
+ pstack migrate --source=../field_notes --adapter=flutter --dry-run
762
+ ```
763
+
764
+ #### Importing from an Nx workspace (v0.10.0)
765
+
766
+ `pstack migrate --source=../nx-repo` copies the Angular apps, Angular/TS libs and Flutter projects
767
+ of an Nx 15–17 workspace into this one (`nx-workspace` adapter). Projects keep their paths, names and
768
+ import aliases, so no source file is rewritten.
769
+
770
+ ```bash
771
+ pstack migrate --source=../nx-repo --detect # project kinds, what can be migrated
772
+ pstack migrate --source=../nx-repo # every supported project
773
+ pstack migrate --source=../nx-repo --projects=portal,admin # these, plus the libs they import
774
+ pstack migrate --source=../nx-repo --projects=portal --no-deps # only portal
775
+ pstack migrate --source=../nx-repo --prefix=legacy # projects named legacy-<name>
776
+ ```
777
+
778
+ - Projects come from `project.json` files, `workspace.json` and an Nx `angular.json`. Kinds:
779
+ Angular app (`browser` / `webpack-browser` build), lib (no build, or an Angular, `js` or
780
+ run-commands build), Flutter app or package (`pubspec.yaml`), Ionic app (an Angular app with a
781
+ Capacitor or Ionic config; see below). e2e, Angular 17+ application-builder, Angular SSR,
782
+ React/Node and root projects are listed in the report as not supported yet.
783
+ - `--projects` brings the libs the named projects need: path-alias imports, `implicitDependencies`
784
+ and pubspec `path:` dependencies. `--no-deps` turns that off.
785
+ - `--prefix` renames the projects, their target references and implicit dependencies; paths and
786
+ aliases stay as they are.
787
+ - `@nrwl/*` executors become `@nx/*` (and `@nrwl/nx` in ESLint configs becomes `@nx`); the `@nx/*`
788
+ plugins they use, and the ng-packagr build packages for buildable Angular libs, are added at the
789
+ workspace's versions. The source's own Nx packages are not copied.
790
+ - Angular apps get the polystack `release` target, tags and npm scripts; Flutter apps get the
791
+ polystack Flutter targets, `env/*.json` and npm scripts.
792
+ - The source aliases of copied projects go into `tsconfig.base.json`, named inputs the targets use
793
+ into `nx.json`, and `jest.preset.js` when Jest targets need it. The report lists the root ESLint
794
+ `depConstraints`, `tsconfig` compiler options and options pointing outside the copied projects.
795
+ - Nothing is written when a project path, a project name or an alias already exists in the
796
+ workspace, or the Angular majors differ (`--force-angular`).
797
+
798
+ The report is `docs/migrations/<name>.md`; `--name` defaults to the source package name.
799
+
800
+ #### Multi-app Nx sources and shared folders (v0.24.0)
801
+
802
+ Nx sources with several apps (including Nx 15 repos on `@nrwl/*`) that keep shared files outside
803
+ their projects come over in one run:
804
+
805
+ - **Folders that are not projects** are copied to the same path. A folder is copied when the
806
+ projects use it:
807
+
808
+ - from `assets`, `styles`, `scripts`, `fileReplacements` and
809
+ `stylePreprocessorOptions.includePaths`;
810
+ - from `tsconfig.base.json` (`typeRoots`, `include`);
811
+ - from files the root npm scripts run (`node tools/scripts/build.js`);
812
+ - from imports that leave a project: relative imports, imports through `baseUrl: "."` such as
813
+ `environments/<app>/…`, and SCSS `@use`/`@import`/`@forward`.
814
+
815
+ Typical ones are an assets or styles folder under `libs/`, a root `environments/` folder and
816
+ `tools/`. Root files those scripts or options use (e.g. `postbuild.js`) are copied too. Files the
817
+ workspace already has (for example `tools/config/*.json`) are kept and listed. Possible secrets
818
+ (now also `*.key` and `*.pfx`) are never copied. Paths into projects that were not selected are
819
+ reported, not followed.
820
+
821
+ - **Root `package.json`:** `overrides`, `browser` and `engines` are carried over (missing keys
822
+ only; differing ones are listed). An `engines.node` range that leaves out the Node in the
823
+ workspace's `.nvmrc` is reported instead of carried (since v0.27.1), because the workspace
824
+ installs with `engine-strict`. A pnpm or Yarn workspace gets a note to move the overrides.
825
+ Source npm scripts the workspace does not have are kept, so a repo that builds through its own
826
+ scripts (`build:<app>:<env>` → `node tools/scripts/build.js --project=<app> --env=<env>`) can keep
827
+ using them. Scripts of the same name keep the source command, and the polystack ones are added
828
+ only for names that are free. Three kinds of scripts behave differently:
829
+ - Lifecycle scripts (`postinstall`, `prepare`, …) are never carried over; they are listed.
830
+ - Scripts that name a project that was not imported are dropped and listed.
831
+ - With `--prefix`, project names in nx/ng commands of the kept scripts (`nx <verb> <p>`,
832
+ `nx run <p>:…`, `--project=<p>`) are renamed. A custom script (`node build.js --project=<p>`)
833
+ keeps the source name, because it looks the name up itself (base hrefs, env folders); the
834
+ report lists these scripts, so you can update the `nx build` call inside them.
835
+ - **Release target:** added next to those scripts. A source's own `release` target is left as it
836
+ is.
837
+
838
+ - `envProject` comes from the build's `fileReplacements` (`environments/<x>/environment.<env>.ts`).
839
+ - In that per-env layout (`environment.dev.ts`, no `environment.ts`) the executor reads
840
+ `environment.<env>.ts` for UAT and PROD; DEV is not encrypted.
841
+ - Base hrefs come from `nx build … --base-href` flags in the npm scripts, or from a map in the
842
+ custom build script whose name says base href (`const BASE_HREF = { app: { uat: '/x/' } }` or
843
+ `{ app: '/x/' }`). Apps whose base hrefs can't be read, or are read differently from two maps,
844
+ are listed.
845
+
846
+ The report says to keep using the repo's scripts until the release target covers their extra
847
+ steps.
848
+
849
+ - **CSP nonce patch:** in Angular and Ionic apps, a `main.ts` side-effect import of a local nonce
850
+ patch that reads the nonce the way the library does (`window.__cspNonce` or the `csp-nonce` meta
851
+ tag) is replaced by `@mouryaamit/nx-polystack/runtime/csp-nonce`. Other local patches are kept,
852
+ with the library import added before them. Apps without one get the import first (after any
853
+ `/// <reference>` lines). Local patch files are not deleted.
854
+ - **Nx 15 specifics:**
855
+ - `@nrwl/*` executors and ESLint configs become `@nx/*`.
856
+ - Wildcard aliases (`@scope/lib/*`) of copied libraries are kept.
857
+ - `baseUrl` is set in `tsconfig.base.json` when the workspace has none and the code imports
858
+ through it.
859
+ - A Jest major below 29 gets a note: the workspace's `@nx/jest` needs Jest 29 and
860
+ `jest-preset-angular` 13.
861
+
862
+ #### CSP nonce at runtime (v0.24.0)
863
+
864
+ `@mouryaamit/nx-polystack/runtime/csp-nonce` is a small browser script that new Angular and Ionic
865
+ apps import first in `main.ts`. Under a strict Content-Security-Policy, Angular 15 and webpack add
866
+ `<style>`, `<script>` and stylesheet `<link>` elements at runtime without a nonce, and the browser
867
+ blocks them (Angular 15 has no built-in nonce support).
868
+
869
+ - **What it patches:** it gives these elements the page nonce when they are inserted, through any
870
+ of:
871
+ - `appendChild`/`insertBefore`/`replaceChild` on the document, on elements and on shadow roots;
872
+ - `append`/`prepend`/`before`/`after`/`replaceWith`/`insertAdjacentElement`.
873
+ - **Where the nonce comes from:** `window.__cspNonce`, or the `csp-nonce` meta tag that
874
+ `release --secure` writes. An SSI directive the server did not process, or a placeholder such as
875
+ `random-csp-nonce`, counts as no nonce, and nothing is patched.
876
+ - **Existing apps:** `pstack update` (migration `add-csp-nonce-import`) adds the import to apps
877
+ with the polystack release target. It never removes a local nonce patch import.
878
+
879
+ #### Env encryption settings (v0.25.0)
880
+
881
+ Release builds (`nx run <app>:release:<env>`) encrypt env values for every env except DEV. The
882
+ settings live in `nx.json`:
883
+
884
+ ```json
885
+ "pstack": { "envEncryption": {
886
+ "mode": "listed",
887
+ "cipher": "cryptojs",
888
+ "keySources": ["commit"],
889
+ "metaName": "x-build",
890
+ "keys": { "default": [], "web": ["password", "token"] },
891
+ "format": "raw",
892
+ "profileFiles": [],
893
+ "publicKeys": ["production", "envName", "appName", "timeStamp"],
894
+ "stamp": { "timeField": "timeStamp", "branchField": "branch", "timezone": "UTC",
895
+ "format": "DD MMM YYYY hh:mm:ss A z" }
896
+ } }
897
+ ```
898
+
899
+ - `mode: "listed"` (default) encrypts the keys of the env project (`keys.<envProject>`, else
900
+ `keys.default`), wherever `key: '<value>'` appears in the file (as before, the key is not
901
+ anchored: `key` also matches `apiKey:`). `keys.default` is empty unless you list keys, so nothing
902
+ is encrypted by default, as before v0.25.0. A listed key whose value is not a plain string is
903
+ left alone with a warning.
904
+ - `mode: "all"` encrypts every top-level string field except `publicKeys`. The stamp fields are
905
+ filled first and stay plain only when listed there: the default list has `timeStamp` but not the
906
+ branch field, so since v0.27.0 the branch is encrypted too (add it to `publicKeys` with
907
+ `pstack encryption --add-public=branch` to keep it plain). A stamp field that is not a string
908
+ literal is left as it is. Any other non-public field that is not a literal (a variable, a call,
909
+ `${…}` in a template), an entry without `key:` (shorthand, spread, computed key) or a missing
910
+ `environment = { … }` object fails the build. Profile values equal to a stamp value are not
911
+ encrypted for it.
912
+ Use it only when the app decrypts every field (`envReady` of `runtime/env-secret`, see Env
913
+ secrets in the browser).
914
+ - With `cryptojs` the ciphertext is unchanged: CryptoJS AES with the build's commit as the
915
+ passphrase, the same commit that goes into `<meta name="<metaName>">`. This is obfuscation; real
916
+ secrets belong on a server. The commit is taken as CI gives it: on GitHub Actions, GitLab,
917
+ Bitbucket, CircleCI and Azure that is the full 40-character SHA (meta tag and key still match).
918
+ Build errors never print values.
919
+ - Changing `metaName` needs the same change in apps that read the key from the meta tag.
920
+ - `cipher`: `cryptojs` (default) or `aes-gcm` (v0.28.0, see AES-GCM env encryption).
921
+ `keySources` (v0.28.0; replaces `keySource`, which `pstack update` renames) lists the
922
+ aes-gcm key factors (default `["commit"]`); `cryptojs` always uses the commit.
923
+
924
+ **Secrets out of git.** UAT/PROD env files may hold `${NAME}` placeholders in quoted strings. The
925
+ release build fills them from environment variables, then from `.env.local` at the workspace root
926
+ (`NAME=value` lines; gitignored), and fails listing every missing name. The dev env file must keep
927
+ literal values (`nx serve` does not fill placeholders); a placeholder there fails `release:dev`.
928
+
929
+ **Build stamp.** When the env file declares `timeStamp` / `branch` (the `stamp` field names), the
930
+ release build fills them with the build time (`timezone`, `format` tokens `YYYY MM MMM DD HH hh mm
931
+ ss A z`, optional `timezoneLabel` for `z`) and the branch. Branch and commit come from CI variables
932
+ (Jenkins, GitHub Actions, GitLab, Bitbucket, CircleCI, Azure Pipelines) or git. Text in `[ ]` is
933
+ kept as is (`[at] HH:mm`).
934
+
935
+ **Safe restores.** The env file is backed up under `node_modules/.cache/nx-polystack/env-backup`
936
+ and restored after the build, also when it fails; a build that was killed is repaired by the next
937
+ release build of that env file (unless the file was edited since; then it is kept). Release builds
938
+ that share an env file wait for each other (on one machine; builds in different containers
939
+ sharing one workspace are not coordinated). The Angular build runs with `--skip-nx-cache`. While a
940
+ release build runs, the env file holds filled and encrypted values: don't commit it then.
941
+
942
+ **`pstack encryption`** shows the settings; `--mode`, `--add-key` / `--remove-key`
943
+ (`--project=<envProject>`), `--add-public` / `--remove-public`, `--meta-name`, `--timezone` and
944
+ `--stamp-format` change them. Needs nx-polystack 0.25.0 in the workspace.
945
+
946
+ **Updating.** `pstack update` (migration `env-encryption-config`) moves
947
+ `tools/config/encrypt-keys.json` into `nx.json` with the same keys (mode `listed`), removes the
948
+ file and adds `.env.local` to `.gitignore`. Builds encrypt the same fields as before. Until then the
949
+ executor still reads the old file and prints a warning.
950
+
951
+ #### Env secrets in the browser (v0.26.0)
952
+
953
+ `@mouryaamit/nx-polystack/runtime/env-secret` decrypts what the release build encrypted
954
+ (`crypto-js` comes from the workspace's dependencies). Call it once in `main.ts`, before
955
+ `AppModule` is imported or bootstrapped:
956
+
957
+ ```ts
958
+ import { environment } from '../../../environments/web/environment';
959
+ import {
960
+ envReadySync,
961
+ envSecret,
962
+ envSecretAsync,
963
+ } from '@mouryaamit/nx-polystack/runtime/env-secret';
964
+
965
+ envReadySync(environment, { sync: ['uname'] }); // or { inPlace: true }, or { sync: 'all' }
966
+
967
+ envSecret('uname'); // sync: decrypted at startup, or on first call and cached
968
+ await envSecretAsync('password'); // decrypted on every call, nothing kept
969
+ ```
970
+
971
+ - `inPlace: true` decrypts every encrypted value of `environment` (nested objects and arrays too),
972
+ so code reading `environment.x` gets plaintext.
973
+ - `sync` decrypts the listed top-level fields (or `'all'`) at startup into a private cache, without
974
+ changing `environment`.
975
+ - `envReady()` is the same as a Promise; with `cipher: aes-gcm` it also decrypts `ENC2(...)`
976
+ values (see AES-GCM env encryption).
977
+ - `getBuildMeta()`, `decryptEnvValue(value)`, `isEncryptedValue(value)` and `decryptTree(obj)` (in
978
+ place, any object) are exported too. The module is an ES module; `require()` users such as Jest get
979
+ a CommonJS copy.
980
+ - Values that are not encrypted (`nx serve`, a plain build) are returned as they are. A value that
981
+ cannot be decrypted is returned unchanged with one console warning (never the value).
982
+
983
+ **Build side.** `format: "enc"` writes values as `ENC(<ciphertext>)` (new workspaces; a committed
984
+ value already in that form fails the build); `"raw"` keeps the bare ciphertext. `profileFiles`
985
+ (e.g. `["app.profile.ts"]`, next to the env file) are encrypted too: string values of
986
+ sensitive-looking keys at any depth (password, pin, otp, secret, uname, token, apiKey, clientId…;
987
+ not names of things such as `otpField`, `getOtp`, a bare `key`), and any string equal to a value
988
+ encrypted from the env file. `pstack encryption --format=enc --profile-files=app.profile.ts`
989
+ changes them.
990
+
991
+ **`:migrate`.** When an Nx source encrypts its env files with its own `tools/**/encrypt-env.js`
992
+ (`ENC(` marker and a `PUBLIC_ENV_KEYS` list), the workspace gets mode `all`, format `enc`, those
993
+ public keys, `profileFiles` when `app.profile.ts` exists and the stamp fields the env files
994
+ declare — unless the workspace's settings were already changed or other apps already build with
995
+ them (the settings apply to every app); then they are kept and the report lists the suggestion. A copied `env-secret.ts` of the
996
+ known shape (CryptoJS, `ENC(`, `envSecret` + `decryptEnvironment`, no other exports, key type
997
+ `string`) becomes a wrapper of the runtime module with the same exports, so `env-init.ts` and every
998
+ caller keep working; other shapes are kept and reported. In profile files, values equal to an
999
+ encrypted env value are encrypted only as property values or array items (never import paths,
1000
+ type literals or comparisons), and sensitive keys whose values are not plain strings are named in a
1001
+ warning.
1002
+
1003
+ #### AES-GCM env encryption (v0.28.0)
1004
+
1005
+ `pstack encryption --cipher=aes-gcm` switches release builds to AES-256-GCM (Web Crypto). Every
1006
+ build makes a new 32-byte random key and takes the UTC build time; your `keySources` (at least one
1007
+ of `commit`, `salt`, `env`, `custom`; `--key-sources=commit,salt`) are mixed in with HKDF-SHA256.
1008
+ Values are written as `ENC2(...)` and bound to the name of the property that holds them (array
1009
+ items: the array's property name), so a value moved to another field does not decrypt.
1010
+
1011
+ ```bash
1012
+ pstack encryption --cipher=aes-gcm --key-sources=commit,salt
1013
+ pstack encryption --app=web --key-split=meta-bundle-asset
1014
+ pstack encryption --app=web --domains='uat=uat.example.com,example.in;prod=example.com'
1015
+ pstack encryption --app=web --domains=uat= # removes the uat list
1016
+ pstack encryption --app=web --include-www=false --on-mismatch=warn
1017
+ ```
1018
+
1019
+ - The random key is split: one share in `<meta name="x-build">` (`metaName`), one in the bundle
1020
+ (`keySplit: meta-bundle`, the default), and with `meta-bundle-asset` a third in
1021
+ `assets/pstack-k.<hash>.bin`. The meta share and the asset go next to the served `index.html`
1022
+ (`<outputPath>`, or `<outputPath>/browser` for the Angular application builder); an aes-gcm
1023
+ build without an `index.html` there fails. `--app=<project>` sets `--key-split`, `--domains`,
1024
+ `--include-www` and `--on-mismatch` on that app's release target.
1025
+ - `salt`: `tools/config/env-salt`, created on first use; commit it; `--rotate-salt` renews it.
1026
+ `env`: `PSTACK_ENV_KEY` at build time. The `salt` and `env` values are written into the bundle,
1027
+ like the commit: use a dedicated random value, never a real secret. `custom`:
1028
+ `PSTACK_CUSTOM_KEY` at build time and `envReady(environment, { getKey })` in the app (e.g.
1029
+ fetched from your server) — the only source that stays out of the shipped files.
1030
+ - Domain lock per app and configuration: `--domains=<conf>=<hosts>[;<conf>=<hosts>…]`
1031
+ (`example.com` also allows `www.example.com` unless `--include-www=false`; `*.example.com` any
1032
+ subdomain; an empty list removes the lock). `--on-mismatch=block` (default) leaves the values
1033
+ encrypted on other hosts; `warn` decrypts with a console warning, for a rollout. `localhost`,
1034
+ `127.0.0.1`, `[::1]` and `capacitor:` / `ionic:` origins are never locked. It deters re-hosting
1035
+ a copied build; it is not protection.
1036
+ - The build fails before it touches any file when `PSTACK_ENV_KEY` / `PSTACK_CUSTOM_KEY` is
1037
+ missing for a listed source, a host is not valid (`@`, `\`, `%`, a wildcard on a single
1038
+ label or an IPv4 address, a path without a scheme) or `keySplit` is unknown. In
1039
+ `mode: "listed"`, a listed key found outside `environment = { … }` or without a property name
1040
+ fails the build too.
1041
+ - Switching rewrites `main.ts` to `await envReady(environment, { inPlace: true })` before
1042
+ bootstrap (with `metaName` when it is not `x-build`) and lists code that reads env fields at
1043
+ import time (those values are still encrypted then). `envSecret()` works after that (it throws on
1044
+ a value still in `ENC2(...)`); `envSecretAsync()` decrypts on use. `envReadySync()` leaves
1045
+ `ENC2(...)` values alone, so an `env-init.ts` that runs at import keeps working.
1046
+ - Objects outside `environment` (e.g. profiles): `await decryptTreeAsync(profile)` after
1047
+ `envReady`. An `env-secret.ts` wrapper written by `:migrate` has `decryptEnvironmentAsync(obj?)`
1048
+ (no argument: the environment); switching adds it to wrappers written before v0.28.0.
1049
+ - Web Crypto needs a secure context: serve the app over https (or localhost).
1050
+ - The key ships with the page (except `custom`), so this hides values; real secrets belong on a
1051
+ server.
1052
+ - `pstack update` (migration `env-encryption-key-sources`) renames `keySource` to `keySources`.
1053
+
1054
+ #### Importing an Ionic app (v0.11.0)
1055
+
1056
+ `pstack migrate --source=../ionic-app` imports a standalone Ionic Angular app that uses Capacitor
1057
+ (`@ionic/angular` plus a `capacitor.config.*`) with the `ionic` adapter. Ionic apps in an Nx import
1058
+ (`ionic-app` projects) get the same treatment. The app ends up in the shape `pstack app --type=ionic`
1059
+ generates:
1060
+
1061
+ - Native packages (Capacitor and Cordova plugins: `@capacitor/*`, names containing `capacitor`,
1062
+ `cordova-*`, `@awesome-cordova-plugins/*`, `@ionic-native/*`, and any installed package that
1063
+ declares a `capacitor` or `cordova` section) are listed in the app's own `package.json` at the
1064
+ source's versions, so `cap sync` finds them. The ones the copied code imports stay in the root
1065
+ `package.json` too, because the web build resolves them from there; the rest (the Capacitor CLI,
1066
+ platform packages, plugins used only natively) are only in the app's `package.json`.
1067
+ - With several Ionic apps in one Nx import, each app gets the platform packages, the plugins it or
1068
+ the shared code imports, and the plugins no copied code imports.
1069
+ - An Angular app with Capacitor but without `@ionic/angular` is handled the same way (no ionicons
1070
+ asset).
1071
+ - `android/` and `ios/` are copied without build output (Gradle `build` and `release` folders,
1072
+ Pods, DerivedData, the generated Cordova plugin projects, the web assets and config `cap sync`
1073
+ copies in) or `local.properties`.
1074
+ - The build output moves from `www` to `dist/apps/<app>`, and `webDir` in the Capacitor config
1075
+ points there. When `webDir` is not a plain string, the report says what to set.
1076
+ - The release target builds with `type: ionic`; `cap-sync`, `cap-open` and `cap-add` targets and
1077
+ the `build:<app>:<env>:android|ios` / `open:<app>:android|ios` scripts are added. `@nxext/*` and
1078
+ `@ionic/angular-toolkit` targets are dropped.
1079
+ - The report's Ionic section lists the package split, the `webDir` change, the platforms copied
1080
+ and any Cordova plugins to check against Capacitor.
1081
+
1082
+ ```bash
1083
+ pstack migrate --source=../field-notes
1084
+ npm install
1085
+ npx nx run field-notes:release:prod
1086
+ npx nx run field-notes:cap-sync --platform=android
1087
+ ```
1088
+
1089
+ Ionic 6 and Capacitor majors other than 5 are accepted with a note. Cordova-only apps (`config.xml`
1090
+ or `ionic.config.json` without a Capacitor config) are refused, in Nx imports too (kind
1091
+ `ionic-cordova`): move them to Capacitor first. Capacitor apps on the Angular 17+ application
1092
+ builder are converted like other Angular 17+ apps (v0.23.0).
1093
+
1094
+ #### Importing a multi-project Angular CLI workspace (v0.12.0)
1095
+
1096
+ `pstack migrate --source=../ng-repo` imports the apps and libraries of an Angular CLI repo whose
1097
+ `angular.json` has several projects (the `angular-workspace` adapter). A repo with a single project
1098
+ still goes to the `angular-cli` (or `ionic`) adapter.
1099
+
1100
+ ```bash
1101
+ pstack migrate --source=../ng-repo --detect # projects and their kinds
1102
+ pstack migrate --source=../ng-repo # every supported project
1103
+ pstack migrate --source=../ng-repo --projects=portal # portal and the libraries it imports
1104
+ pstack migrate --source=../ng-repo --projects=admin --no-deps
1105
+ pstack migrate --source=../ng-repo --prefix=legacy # legacy-<name> projects and folders
1106
+ ```
1107
+
1108
+ - Apps go to `apps/<name>`, libraries to `libs/<name>`. An app at the repo root (the usual first
1109
+ app) is copied without the `projects/` folder and the other projects' folders.
1110
+ - Library aliases that pointed at the build output (`"ui-kit": ["dist/ui-kit"]`) now point at the
1111
+ library source (`libs/ui-kit/src/public-api.ts`, or `lib.entryFile` from `ng-package.json`), so apps
1112
+ build without building the libraries first. Aliases into a project's source follow it to its new
1113
+ folder; others are listed in the report. Imports in the copied code are rewritten (see Import
1114
+ rewriting).
1115
+ - Libraries keep their ng-packagr build (`nx build <lib>`); `ng-package.json` `dest` becomes
1116
+ `dist/libs/<name>`. ng-packagr and its build packages are added when a library builds.
1117
+ - Apps get the release target and npm scripts; apps with a Capacitor config get the Ionic treatment.
1118
+ - Angular 17+ application-builder apps are converted to Angular 15 builders (v0.23.0);
1119
+ server-rendered apps (`angular-ssr`) and e2e-only projects are listed as not supported.
1120
+ - Before anything is written, folders, project names, aliases and the Angular major are checked.
1121
+
1122
+ #### Importing an npm, Yarn or pnpm workspaces repo (v0.18.0, pnpm v0.20.0)
1123
+
1124
+ `pstack migrate --source=../mono` imports a repo whose root `package.json` lists its packages under
1125
+ `workspaces` (npm, Yarn 1 or Yarn Berry, Plug'n'Play included), or whose `pnpm-workspace.yaml` lists
1126
+ them under `packages` (pnpm); this is the `npm-workspaces` adapter. Repos with `nx.json` or a root
1127
+ `angular.json` still go to the Nx and Angular adapters.
1128
+
1129
+ ```bash
1130
+ pstack migrate --source=../mono --detect # packages and their kinds
1131
+ pstack migrate --source=../mono # every supported package
1132
+ pstack migrate --source=../mono --projects=@acme/web # web and the packages it imports
1133
+ pstack migrate --source=../mono --projects=web --no-deps
1134
+ pstack migrate --source=../mono --prefix=legacy # legacy-<name> projects and folders
1135
+ ```
1136
+
1137
+ - Angular app packages (`angular.json` with one application) go to `apps/<name>` with the
1138
+ `angular-cli` treatment; those with a Capacitor config get the Ionic treatment.
1139
+ - TypeScript library packages (an entry from `ng-package.json`, `source`, `types` → `src/…`,
1140
+ `src/index.ts` or `index.ts`) go to `libs/<name>` with a lint target, and their **package name**
1141
+ becomes the tsconfig alias (`"@acme/utils": ["libs/utils/src/index.ts"]`), so imports between
1142
+ packages keep working unchanged.
1143
+ - Project names are the package names without scope (`@acme/web` → `web`); when two packages
1144
+ would share one, both keep their scope (`acme-utils`, `other-utils`). `--projects` takes package
1145
+ or project names.
1146
+ - Dependencies of the source root and the imported libraries are merged into the root
1147
+ `package.json`; app packages merge their own (Angular versions come from the app packages).
1148
+ Workspace packages (`workspace:*` or local versions) are left out; other local `file:`/`link:`
1149
+ paths inside an imported package follow it to its new folder. Lockfiles, `.yarnrc.yml`, `.yarn/`,
1150
+ `.pnp.*` and other root files are not copied; the workspace installs with npm. Outside git, the
1151
+ root `.gitignore` applies to every package.
1152
+ - A dependency on a workspace package that cannot be imported (an ESLint or tsconfig preset, a
1153
+ server) is listed in the report instead of stopping the import; imports of one still do.
1154
+ - Packages that are not Angular/Ionic apps or TypeScript libraries (React, Node servers, CLIs with
1155
+ `bin`) are listed as not supported. Subpath imports (`@acme/utils/x`) and the source root tsconfig
1156
+ options are listed in the report.
1157
+ - pnpm repos:
1158
+ - `catalog:` and `catalog:<name>` versions are taken from `pnpm-workspace.yaml`; an entry the
1159
+ catalogs do not define stops the import before anything is written.
1160
+ - Flat `overrides` (`pnpm.overrides` in `package.json` and `overrides` in `pnpm-workspace.yaml`)
1161
+ become npm `overrides`; entries with selectors (`a>b`, `pkg@<2`), removals (`-`) or
1162
+ `workspace:`/`link:`/`file:` values are listed in the report. An override of a package the
1163
+ import added as a direct dependency also sets that dependency's version (npm refuses an
1164
+ override that differs from it); one the workspace already depends on at another version is
1165
+ reported.
1166
+ - `patchedDependencies`, `.pnpmfile.cjs`, `.npmrc` and the other pnpm settings are listed in the
1167
+ report, not carried over. `pnpm-workspace.yaml`, `pnpm-lock.yaml` and `.pnpmfile.cjs` are not
1168
+ copied.
1169
+ - `pnpm-workspace.yaml` is read with a small reader: anchors, aliases, tags, block scalars
1170
+ (`|`, `>`) and flow lists over several lines stop the import with the line number.
1171
+ - The Nx, Angular CLI and Ionic imports resolve `catalog:` specs in the source `package.json` the
1172
+ same way; an unknown entry, or a `catalog:` spec without pnpm catalogs (Yarn catalogs are not
1173
+ read), stops the import.
1174
+
1175
+ #### Import rewriting (v0.21.0)
1176
+
1177
+ After the copy, `pstack migrate` rewrites imports in the copied code so it builds in its new place.
1178
+ The source is never changed, and `--rollback` removes the rewritten copies with the rest.
1179
+
1180
+ - **Into another moved project:** a relative import that reaches into another project that moved
1181
+ (`../../../utils/src`) becomes that library's alias when it points at the library entry
1182
+ (`@acme/utils`), otherwise a corrected relative path. The report lists the corrected ones so you
1183
+ can export what they need from the entry instead.
1184
+ - **Through the source `baseUrl`:** `import … from 'src/app/x'` becomes a relative path (or the
1185
+ library alias), unless the workspace `baseUrl` still resolves it to the same file.
1186
+ - **`@nrwl/*`:** becomes `@nx/*` (`@nrwl/nx-plugin` becomes `@nx/plugin`; `@nrwl/nx-cloud`,
1187
+ `@nrwl/tao` and `@nrwl/cli` are listed instead). The report names `@nx/*` packages the
1188
+ workspace does not declare yet.
1189
+ - **SCSS:** relative `@use`, `@import` and `@forward` paths that reach into another moved project
1190
+ are corrected; paths into the source's root `node_modules` point at the workspace's.
1191
+ - **Library subpaths** (npm, Yarn and pnpm imports): `@acme/utils/x` resolves through an added
1192
+ `@acme/utils/*` alias to the package folder.
1193
+
1194
+ Code files are `.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs` and `.cjs` (not `.d.ts`); the
1195
+ rewritten forms are `import`/`export … from`, `import()`, side-effect imports, `require()` and
1196
+ `jest.mock()` / `vi.mock()`. Imports that point outside the imported projects, or at a file that
1197
+ was not copied, are left as they are and listed, unless they still resolve in the workspace.
1198
+ Imports inside one copied project are never changed. ESM-style `.js` specifiers of `.ts` files
1199
+ and `?raw`-style suffixes are understood. A bare specifier is only taken as a `baseUrl` import
1200
+ when a file (or a folder with an `index`) exists there; one that is also a dependency in the
1201
+ source `package.json` is listed instead.
1202
+ Nx imports keep their paths, so their relative imports are left alone. The report's `## Imports`
1203
+ section lists every change. `--no-rewrite-imports` (or `"rewriteImports": false` in a `--config`
1204
+ file) keeps the copies as they were and the report lists what needs a hand edit, as before.
1205
+
1206
+ #### Writing your own adapter (v0.22.0)
1207
+
1208
+ When no built-in adapter fits a source, write one. `pstack migrate --new-adapter=<id>` writes a
1209
+ working starter (`tools/migrate/<id>.adapter.ts`, which imports a static site with an `index.html`)
1210
+ with a Jest spec and `tools/migrate/jest.config.js`, and lists it in `nx.json`:
1211
+
1212
+ ```json
1213
+ {
1214
+ "pstack": {
1215
+ "migrateAdapters": ["./tools/migrate/legacy-site.adapter.ts", "@acme/pstack-adapter-x"]
1216
+ }
1217
+ }
1218
+ ```
1219
+
1220
+ Entries are workspace-relative `.js`/`.ts` files or installed package names. A module exports one
1221
+ adapter or a list (`default`, `adapters`, `adapter`, or `module.exports`).
1222
+
1223
+ - **TypeScript:** `.ts` files are transpiled with the workspace's `typescript` and its
1224
+ `tsconfig.base.json` options (no ts-node needed). `paths` aliases are not resolved, and
1225
+ `.mts`/`.cts` files are not supported.
1226
+ - **Adapter packages:** must be CommonJS, and should list nx-polystack as a peer dependency so
1227
+ they use the workspace's copy.
1228
+ - **Trust:** listed adapters run as code on `pstack migrate`, `--detect` included. List only
1229
+ adapters you trust, as with Nx plugins.
1230
+
1231
+ ```ts
1232
+ import {
1233
+ copyIntoTree,
1234
+ defineMigrationAdapter,
1235
+ emptyReportData,
1236
+ MIGRATE_API_VERSION,
1237
+ recordCopy,
1238
+ sourceExists,
1239
+ } from '@mouryaamit/nx-polystack/migrate';
1240
+
1241
+ export default defineMigrationAdapter({
1242
+ apiVersion: MIGRATE_API_VERSION,
1243
+ id: 'legacy-site',
1244
+ label: 'legacy static site',
1245
+ detect: (dir) =>
1246
+ sourceExists(dir, 'site.conf')
1247
+ ? { confidence: 0.9, reasons: ['site.conf'] }
1248
+ : { confidence: 0, reasons: ['no site.conf'] },
1249
+ defaultName: () => undefined,
1250
+ migrate(tree, ctx) {
1251
+ const data = emptyReportData();
1252
+ const copy = copyIntoTree(
1253
+ tree,
1254
+ ctx.sourceDir,
1255
+ ctx.projectRoot,
1256
+ {
1257
+ anyDepth: ['.git'],
1258
+ topLevel: [],
1259
+ },
1260
+ { maxFiles: ctx.maxFiles },
1261
+ );
1262
+ recordCopy(data, copy, '');
1263
+ return data;
1264
+ },
1265
+ });
1266
+ ```
1267
+
1268
+ - **The SDK** (`@mouryaamit/nx-polystack/migrate`) has the adapter and report types, and the
1269
+ helpers the built-in adapters use:
1270
+ - `copyIntoTree`, which applies skip rules, leaves out possible secrets, honours `.gitignore`
1271
+ and enforces `--max-files`;
1272
+ - `recordCopy` and `emptyReportData`;
1273
+ - `mergeDependencies` and `classifyDependencySpec`;
1274
+ - the source readers, `kebabName`, `upTo` and `setProjectTags`.
1275
+ - **Same treatment as the built-ins:** listed adapters take part in `--detect` (inside a workspace),
1276
+ `--adapter=<id>`, `--config` and `--rollback`. Copies made with `copyIntoTree` + `recordCopy` get
1277
+ import rewriting and the report's skipped-paths and secrets lists.
1278
+ - **Checks:**
1279
+ - an adapter must declare `apiVersion: 1` (`MIGRATE_API_VERSION`);
1280
+ - its id must be kebab-case and used by no built-in or other listed adapter;
1281
+ - it needs `label`, `detect`, `defaultName` and `migrate` (plus `preflight` for
1282
+ `kind: 'workspace'`).
1283
+ Anything else stops the run, naming the `nx.json` entry.
1284
+ - **Ties and errors:** built-ins are tried first, so they win ties. An adapter whose `detect()`
1285
+ throws scores 0, with the error as its reason.
1286
+ - **CLI version:** the global `pstack` delegates to the workspace's nx-polystack, which must be
1287
+ v0.22.0 or later to load listed adapters.
1288
+
1289
+ #### Angular 17+ sources (v0.23.0)
1290
+
1291
+ `pstack migrate` imports Angular CLI apps built with the Angular 17+ application builder. The
1292
+ workspace builds with Angular 15, so the targets are converted to the Angular 15 builders. Covered:
1293
+ standalone Angular CLI apps, Ionic apps, multi-project Angular CLI workspaces, and Angular app
1294
+ packages of npm, Yarn and pnpm workspaces. Nx sources on the application builder are still listed as
1295
+ not supported.
1296
+
1297
+ - **Build target:** `@angular-devkit/build-angular:application` and `@angular/build:application`
1298
+ (and `:browser-esbuild` with `browser`/`server`/`ssr` options) become
1299
+ `@angular-devkit/build-angular:browser`. `browser` becomes `main`, an `outputPath` object becomes
1300
+ its `base`, an `index` object keeps `input` and `output`, and a `serviceWorker` path becomes
1301
+ `serviceWorker: true` plus `ngswConfigPath`. Asset objects without `output` get `"/"`. Missing
1302
+ `main`, `index`, `outputPath` and `tsConfig` are filled in, with `aot: true`; a configuration
1303
+ with `optimization: false` gets `buildOptimizer: false`. Options the browser builder does not
1304
+ have (`define`, `loader`, `externalDependencies`, `security`, …), and sub-options Angular 15
1305
+ rejects (`stylePreprocessorOptions.sass`, `optimization.styles.removeSpecialComments`, …), are
1306
+ dropped and listed. The output goes to `outputPath` itself, not to a `browser/` folder inside it.
1307
+ - **Other targets:** `@angular/build:dev-server`, `extract-i18n`, `karma` and `ng-packagr` become
1308
+ the `@angular-devkit/build-angular` builders. Every dev-server, extract-i18n and karma target of
1309
+ the project is checked against Angular 15: `buildTarget` becomes `browserTarget` (added when
1310
+ missing, as Angular 17+ defaults it), asset objects get `output: "/"`, and options Angular 15
1311
+ does not have (`prebundle`, `builderMode`, …) are dropped and listed. Other `@angular/build`
1312
+ targets (`unit-test`) are kept and listed: they cannot run on Angular 15.
1313
+ - **i18n:** a `subPath` (Angular 17.2+) is listed; Angular 15 names locale folders after the
1314
+ locale.
1315
+ - **tsconfig:** TypeScript 5-only compiler options are fixed for TypeScript 4.9:
1316
+ `moduleResolution: "bundler"` becomes `"node"`, `module: "preserve"` becomes `"es2022"`, an
1317
+ ES2023+ `target` or `lib` becomes ES2022, and `verbatimModuleSyntax`, `allowImportingTsExtensions`
1318
+ and the like are removed.
1319
+ - **Server rendering:** an app whose build sets `server`, `ssr`, `prerender` or `appShell` (or that
1320
+ has a server, ssr-dev-server, prerender or app-shell target) is refused before anything is
1321
+ written; in a workspace it is listed as `angular-ssr`. Angular 15 Universal apps (browser builder
1322
+ plus a server target) keep their builders and migrate as before.
1323
+ - **Code (report only):** the report's Angular section lists files that use Angular 16+ code
1324
+ Angular 15 cannot compile: template control flow (`@if`, `@for`, `@switch`, `@defer`, `@let`),
1325
+ signal APIs (`signal`, `computed`, `effect`, `input`, `output`, `model`, `viewChild`, …),
1326
+ `@angular/core/rxjs-interop`, and newer providers (`withFetch`, `provideAnimationsAsync`,
1327
+ `provideZoneChangeDetection`, …). Nothing is rewritten.
1328
+ - **Angular version:** a source on another Angular major still needs `--force-angular`; the
1329
+ workspace's Angular packages are kept.
1330
+ - **CLI version:** the global `pstack` delegates to the workspace's nx-polystack, which must be
1331
+ v0.23.0 or later.
1332
+
1333
+ ### `:infra` generator / `pstack infra` (v0.9.0)
1334
+
1335
+ Same options as `pstack infra` (§3c): `with`, `ci`, `ciCache`, `flutter`, `upgradeSchedule`, `upgradeScope`,
1336
+ `force`, `skipFormat`.
1337
+
1338
+ ```bash
1339
+ npx nx g @mouryaamit/nx-polystack:infra --with=docs,ci --ci=jenkins
1340
+ ```
1341
+
1342
+ ### `:app` generator schema
1343
+
1344
+ ```jsonc
1345
+ {
1346
+ "name": "portal", // string — required
1347
+ "type": "angular", // "angular" | "flutter" — required
1348
+ "tags": ["platform:web"], // string[] — optional
1349
+ "cspConnectSrc": "https://..." // string — optional, angular only
1350
+ }
1351
+ ```
1352
+
1353
+ ---
1354
+
1355
+ ## 7. Nx plugin usage — executors
1356
+
1357
+ Executors run as Nx targets after the plugin is installed as a dev dependency.
1358
+
1359
+ ### `:build` — Angular / Ionic build pipeline
1360
+
1361
+ Replaces the legacy `tools/scripts/build.js` orchestrator. Runs the full pipeline:
1362
+
1363
+ ```
1364
+ encrypt-env → nx build → restore env
1365
+ [→ leak check] (non-DEV, leakCheck)
1366
+ [→ source-map check] (non-DEV, sourceMaps)
1367
+ [→ strip / drop console] (non-DEV, stripComments / dropConsole)
1368
+ [→ obfuscate] (non-DEV, obfuscate: light)
1369
+ [→ SRI hash swap] (non-DEV, sri: true)
1370
+ → strip-exif (PROD) → inject-meta
1371
+ [→ inject-nonce] (if secure: true)
1372
+ [→ inject-sri] (if sri: true; recomputes Angular's values)
1373
+ → ngsw.json hashes (when present)
1374
+ ```
1375
+
1376
+ The `nx build` step runs the app's Angular `build` target (`buildTarget`). Generated Angular apps register this
1377
+ executor as the `release` target; the Angular builder lives on `build`.
1378
+
1379
+ **`project.json` target example:**
1380
+
1381
+ ```jsonc
1382
+ {
1383
+ "release": {
1384
+ "executor": "@mouryaamit/nx-polystack:build",
1385
+ "outputs": ["{options.outputPath}"],
1386
+ "options": {
1387
+ "type": "angular",
1388
+ "outputPath": "dist/apps/portal",
1389
+ "envProject": "portal",
1390
+ "buildTarget": "portal:build"
1391
+ },
1392
+ "configurations": {
1393
+ "dev": { "env": "DEV", "buildConfiguration": "development" },
1394
+ "uat": {
1395
+ "env": "UAT",
1396
+ "buildConfiguration": "uat",
1397
+ "leakCheck": "fail",
1398
+ "sourceMaps": "fail",
1399
+ "stripComments": true,
1400
+ "dropConsole": ["log", "debug", "warn"]
1401
+ },
1402
+ "prod": {
1403
+ "env": "PROD",
1404
+ "buildConfiguration": "production",
1405
+ "leakCheck": "fail",
1406
+ "sourceMaps": "fail",
1407
+ "stripComments": true,
1408
+ "dropConsole": ["log", "debug", "warn"]
1409
+ }
1410
+ },
1411
+ "defaultConfiguration": "dev"
1412
+ }
1413
+ }
1414
+ ```
1415
+
1416
+ **Schema options:**
1417
+
1418
+ | Option | Type | Default | Description |
1419
+ | -------------------- | ---------------------------- | ----------------- | ----------------------------------------------------------------------- |
1420
+ | `type` | `"angular" \| "ionic"` | — | App type |
1421
+ | `outputPath` | `string` | — | Build output directory |
1422
+ | `envProject` | `string` | — | Folder name under `environments/` |
1423
+ | `env` | `string` | — | `DEV`, `UAT`, `PROD` or custom (e.g. `QA`); set via Nx `configurations` |
1424
+ | `buildTarget` | `string` | `<project>:build` | Angular target to run, exactly `<project>:<target>` |
1425
+ | `buildConfiguration` | `string` | see below | Configuration of `buildTarget` |
1426
+ | `secure` | `boolean` | `false` | Inject CSP nonce SSI placeholders |
1427
+ | `sri` | `boolean` | `false` | Integrity for every chunk (`--subresource-integrity`, hashes refreshed) |
1428
+ | `leakCheck` | `fail\|warn\|off` | `off` | non-DEV: plaintext of encrypted env values in the output (below) |
1429
+ | `sourceMaps` | `fail\|warn\|off` | `off` | non-DEV: source maps in the output |
1430
+ | `stripComments` | `boolean` | `false` | non-DEV: remove comments from built JS, CSS, `index.html` |
1431
+ | `dropConsole` | `string[]` | `[]` | non-DEV: console methods removed from built JS |
1432
+ | `obfuscate` | `off\|light\|medium\|strong` | `off` | non-DEV: obfuscate main and lazy chunks (below) |
1433
+ | `obfuscateOptions` | `object` | — | non-DEV: javascript-obfuscator overrides on top of the level |
1434
+ | `harden` | `boolean` | `false` | Replaced: read as `stripComments` + `dropConsole` defaults; no script |
1435
+ | `baseHref` | `string` | — | Forwarded to Angular CLI `--base-href` |
1436
+
1437
+ **`buildTarget` / `buildConfiguration`.** The executor runs
1438
+ `npx nx run <buildTarget>:<buildConfiguration> --outputPath=<outputPath>`. When `buildConfiguration` is unset it
1439
+ falls back to `production` for `PROD`, `uat` for `UAT`, and `development` for anything else. `buildTarget` must be
1440
+ `<project>:<target>`; any other format is an error.
1441
+
1442
+ **Self-reference error.** `buildTarget` must not point at the target that is running (for example `portal:release`
1443
+ with `buildTarget: portal:release`). The executor stops with
1444
+ `buildTarget "<x>" points at this target. Run "pstack update" (migration angular-release-target) or set buildTarget to the Angular build target.`
1445
+ This is what an app generated by v0.3.x hits, because its `build` target used this executor.
1446
+
1447
+ **Custom environments (QA).** `env` is free-form. `env: "QA"` reads `environments/<envProject>/environment.qa.ts`
1448
+ (`DEV` reads `environment.ts`); EXIF stripping stays PROD-only. `pstack env --name=qa --app=portal` adds the `qa`
1449
+ configuration to `build`, `serve` and (when present) `release`, plus a `build:<app>:qa` npm script
1450
+ (see "Adding an environment later"):
1451
+
1452
+ ```bash
1453
+ pstack env --name=qa --app=portal
1454
+ npx nx run portal:release:qa
1455
+ ```
1456
+
1457
+ **Release hardening (v0.29.0).**
1458
+
1459
+ The polystack `release` target (`@mouryaamit/nx-polystack:build`) can check and clean the build
1460
+ output of a UAT or PROD release. The options are set per release configuration; DEV builds skip
1461
+ every step.
1462
+
1463
+ | Option | Values | New apps (uat, prod) | What it does |
1464
+ | --------------- | -------------------------------------------------------- | ------------------------ | ----------------------------------------------------------------------- |
1465
+ | `leakCheck` | `fail`, `warn`, `off` | `fail` | Plaintext of a value encrypted in this build found in the output |
1466
+ | `sourceMaps` | `fail`, `warn`, `off` | `fail` | `.map` files or `sourceMappingURL` comments in the output |
1467
+ | `stripComments` | boolean | `true` | Removes comments from the built JS, CSS and the served `index.html` |
1468
+ | `dropConsole` | list of `log`, `debug`, `warn`, `info`, `error`, `trace` | `["log","debug","warn"]` | Removes those console calls from the built JS (`info`/`error` are kept) |
1469
+
1470
+ ```jsonc
1471
+ "uat": {
1472
+ "env": "UAT",
1473
+ "buildConfiguration": "uat",
1474
+ "leakCheck": "fail",
1475
+ "sourceMaps": "fail",
1476
+ "stripComments": true,
1477
+ "dropConsole": ["log", "debug", "warn"]
1478
+ }
1479
+ ```
1480
+
1481
+ Absent options are off. `fail` lists every hit, then fails the build; `warn` lists them and
1482
+ continues. `LEAK_CHECK=warn` (or `fail`/`off`) overrides `leakCheck` for one run:
1483
+
1484
+ ```bash
1485
+ LEAK_CHECK=warn npx nx run web:release:uat
1486
+ ```
1487
+
1488
+ **Order after the Angular build:** env files restored → leak check → source-map check → strip
1489
+ comments and drop console (one terser pass per JS file) → EXIF strip (PROD) → build meta, aes-gcm
1490
+ key share, CSP nonce, SRI. SRI hashes therefore cover the final files.
1491
+
1492
+ - **Leak check.** Looks for the plaintext of every value encrypted from the env and profile files
1493
+ (4 characters or longer) in the js, mjs, cjs, html, css, json, txt and map files of the served
1494
+ output (`3rdpartylicenses.txt` is skipped). Matches are whole tokens, raw or escaped (JSON,
1495
+ `\uXXXX`, and HTML entities in html files). Messages name the file and the env key, never the
1496
+ value. A value a profile file holds under a non-sensitive key (public by the app's own
1497
+ configuration) is only a warning.
1498
+ - **Source maps.** The hint names the Angular option to change: `"sourceMap": false` in the build
1499
+ configuration.
1500
+ - **Strip and drop console.** `assets/` is never touched. License comments (`/*! … */`) stay when
1501
+ only `dropConsole` is set. SSI (`<!--#…-->`) and IE conditional comments stay in html; html is
1502
+ left alone for SSR hydration (`index.csr.html` or `ngh` attributes). A file terser cannot parse
1503
+ fails the build, naming the file. The Angular service worker's `ngsw.json` hashes are
1504
+ recomputed at the end of the build (v0.30.0).
1505
+ - **terser.** The JS step loads terser from the workspace: keep `terser` in the root
1506
+ `devDependencies` (new apps and the migration add `^5.16.0`). Without it the build fails with "stripComments/dropConsole need terser in the
1507
+ workspace devDependencies".
1508
+ - **`harden`** is replaced. It used to run two scripts that workspaces do not have; now
1509
+ `harden: true` is read as `stripComments: true` plus `dropConsole: ["log","debug","warn"]` when
1510
+ those are unset, with a warning naming the new options. It runs no script.
1511
+ - **`pstack update`** (migration `release-hardening`, 0.29.0) turns the four options on for every
1512
+ release configuration whose `env` is `UAT` or `PROD` (values already set, in the configuration
1513
+ or the target options, are kept), removes `harden` (other non-DEV configurations it applied to
1514
+ get `stripComments` and `dropConsole` instead) and adds terser. Set `leakCheck`/`sourceMaps` to
1515
+ `"warn"` to report only.
1516
+
1517
+ **Obfuscation and integrity (v0.30.0).** Two more release options, also per configuration and
1518
+ skipped for DEV:
1519
+
1520
+ | Option | Values | Default | What it does |
1521
+ | ------------------ | ---------------------------------- | ------- | ----------------------------------------------------------------------------------------- |
1522
+ | `obfuscate` | `off`, `light`, `medium`, `strong` | `off` | Obfuscates main and the lazy chunks (runtime, polyfills, vendor, scripts, styles skipped) |
1523
+ | `obfuscateOptions` | object | — | javascript-obfuscator options on top of the level (CSP-safe subset) |
1524
+ | `sri` | boolean | `false` | Integrity for every chunk; with aes-gcm the app decrypts nothing without it |
1525
+
1526
+ ```bash
1527
+ pstack hardening --app=web # show the settings
1528
+ pstack hardening --app=web --configuration=uat --obfuscate=light --sri
1529
+ pstack hardening --app=web --sri --drop-console=log,debug,warn # every non-DEV configuration
1530
+ ```
1531
+
1532
+ - **Order:** checks → strip / drop console → obfuscate → SRI hash swap → EXIF, meta, key share,
1533
+ CSP nonce → SRI in index.html → `ngsw.json` hashes.
1534
+ - **`obfuscate`** uses `javascript-obfuscator` from the workspace (`pstack hardening` adds
1535
+ `^4.2.2`; run `npm install`). No migration turns it on. Levels, measured on a 2.8 MB Angular
1536
+ chunk (gzip growth):
1537
+
1538
+ | Level | Profile | Gzip |
1539
+ | -------- | ---------------------------------------------------------------------------------------------------------- | --------------------- |
1540
+ | `light` | short (mangled) names, half the strings in a rotated, shuffled array, no wrappers | ≈ +20% |
1541
+ | `medium` | hexadecimal names, three quarters of the strings, string-array wrappers | ≈ +67% |
1542
+ | `strong` | `medium`, plus rc4 string encoding and control-flow flattening (0.1) on the chunk holding the decrypt code | ≈ +210% on that chunk |
1543
+
1544
+ Every level is CSP-safe (`target: browser-no-eval`): no self-defending or debug protection,
1545
+ globals and properties are not renamed, and each file gets its own identifier prefix and a
1546
+ seed from its content. Main often holds the decrypt code and, in production builds without a
1547
+ vendor chunk, the Angular framework: measure start-up time. (v0.31.0: `light` was the
1548
+ `strong` profile in v0.30.x.)
1549
+
1550
+ - **`obfuscateOptions`** tunes the level, e.g. `{ "stringArrayThreshold": 0.3 }` or
1551
+ `{ "identifierNamesGenerator": "mangled" }`. Allowed keys: `stringArray`,
1552
+ `stringArrayThreshold`, `stringArrayRotate`, `stringArrayShuffle`, `stringArrayEncoding`,
1553
+ `stringArrayIndexShift`, `stringArrayWrappersCount`, `stringArrayWrappersType`,
1554
+ `stringArrayWrappersChainedCalls`, `identifierNamesGenerator`, `controlFlowFlattening`,
1555
+ `controlFlowFlatteningThreshold`, `deadCodeInjection`, `deadCodeInjectionThreshold`,
1556
+ `numbersToExpressions`, `simplify`, `splitStrings`, `splitStringsChunkLength`,
1557
+ `transformObjectKeys`, `unicodeEscapeSequence`, `reservedNames`, `reservedStrings`. Anything
1558
+ else (eval-based protection, domain lock, renaming globals or properties, the target) fails the
1559
+ build. `pstack hardening --obfuscate-options='{"stringArrayThreshold":0.3}'` sets it
1560
+ (`none` clears it).
1561
+ - **`sri: true`** passes `--subresource-integrity` to the Angular build, so the webpack runtime
1562
+ checks every lazy chunk and index.html carries `integrity` on its scripts and styles. The
1563
+ hashes Angular wrote are swapped for the hashes of the stripped and obfuscated files, and the
1564
+ index.html values are recomputed, so the browser refuses any file changed after the build. With
1565
+ cipher aes-gcm the build also sets `ri` in `__pstack`: `envReady` rejects with "integrity
1566
+ required" and decrypts nothing while a `<script src>` on the page has no `integrity`
1567
+ attribute. cryptojs builds get the browser check only. The application builder (esbuild) loads
1568
+ lazy chunks with `import()`, which carries no hash: the build warns that they are not covered.
1569
+ - **Integrity set in `angular.json`.** If the Angular build already wrote integrity
1570
+ (`subresourceIntegrity: true`) while pstack `sri` is off, the hashes are still swapped and
1571
+ refreshed after strip and obfuscate. After the swap, every hash in the webpack runtime must match
1572
+ an output file, else the build fails. A `deployUrl` is not supported with `sri`.
1573
+ - **Limits of the runtime check.** It covers same-origin `<script src>` (the files the build
1574
+ serves); third-party scripts such as a tag manager or chat widget are left to your CSP allowlist,
1575
+ and the build lists their hosts. It checks that the attribute is present (the browser checks the
1576
+ value) and does not cover inline scripts. (v0.30.1: v0.30.0 also required integrity on
1577
+ third-party scripts, which blocked decryption on pages that load them.)
1578
+ - **Service worker.** When the output has `ngsw.json`, its `hashTable` is recomputed after every
1579
+ rewrite, so the service worker accepts the final files. With `secure: true` the server rewrites
1580
+ `index.html` (the SSI nonce), so that one entry can never match.
1581
+
1582
+ **Release per environment (v0.32.0).** `pstack build` builds every app for one environment and
1583
+ prints a summary:
1584
+
1585
+ ```bash
1586
+ pstack build --env=uat --all --dry-run # the plan only
1587
+ pstack build --env=uat --all
1588
+ pstack build --env=prod --projects=portal,admin --parallel=2 --continue --report=dist/build.json
1589
+ ```
1590
+
1591
+ - **What it builds:** the release target (`@mouryaamit/nx-polystack:build`) of Angular and Ionic
1592
+ apps, and `build-web` of Flutter apps (`--flutter-platforms=web,android,ios` adds
1593
+ `build-android` / `build-ios`). The configuration is the one named after the env, else the one
1594
+ whose `env` option matches. Apps without one are listed, not failed.
1595
+ - **How:** `npx nx run <app>:<target>:<configuration>`, one at a time with the build output shown;
1596
+ `--parallel=N` (up to 8) runs N at once with each line prefixed by the app name. The first
1597
+ failure stops the run (the rest are listed as skipped) unless `--continue` is given. The exit
1598
+ code is 1 when a build failed.
1599
+ - **Summary:** status, time and output folder size per build, and the total time;
1600
+ `--report=<file>` writes it as JSON too. The size is of the whole output folder, so
1601
+ files left from an earlier build count too; builds of one app (Flutter platforms) never run
1602
+ side by side.
1603
+
1604
+ **Base href per configuration.** `pstack app --base-href=/portal/` writes `baseHref` on the `uat`
1605
+ and `prod` configurations of the release target (Flutter: `build-web`).
1606
+ `pstack release --app=portal` shows them; `--base-href=/portal/` sets every non-DEV
1607
+ configuration (or `--configuration=<name>` only), `--base-href=none` removes it.
1608
+
1609
+ **CSP and server config (v0.33.0).** Each Angular/Ionic app's `csp-allowlist.json` lists the
1610
+ extra sources its pages need; `pstack csp` writes `src/.htaccess` (Apache) and
1611
+ `server/nginx.conf` (Nginx) from it:
1612
+
1613
+ ```bash
1614
+ pstack csp --app=portal # show the policy, write missing files
1615
+ pstack csp --app=portal --add=script-src:https://www.googletagmanager.com,connect-src:https://api.example.com
1616
+ pstack csp --app=portal --remove=connect-src:https://old.example.com
1617
+ pstack csp --app=portal --force # also replace hand-written files
1618
+ ```
1619
+
1620
+ - **Allowlist keys:** `script-src`, `style-src`, `img-src`, `font-src`, `connect-src`,
1621
+ `frame-src`, `media-src`, `worker-src`, `manifest-src`, `form-action`, `frame-ancestors`, plus
1622
+ `permissions-policy` (a string). Sources are hosts (`https://api.example.com`,
1623
+ `https://*.example.com`, `wss://…`, with optional port and path), schemes (`https:`, `wss:`,
1624
+ `data:`, `blob:`), `'self'`, or `'wasm-unsafe-eval'` in `script-src`. Quoted keywords such as `'unsafe-inline'`/`'unsafe-eval'`, `*`,
1625
+ and `data:`/`blob:` in `script-src` are refused.
1626
+ - **Policy:** `script-src 'self' 'nonce-…'` and `style-src 'self' 'nonce-…'` plus the allowlist,
1627
+ `style-src-attr 'unsafe-inline'` (Angular `[style]` bindings), `img-src`/`font-src` with
1628
+ `data:`, `object-src 'none'`, `base-uri 'self'`, `form-action 'self'`,
1629
+ `frame-ancestors 'none'` (or the listed ones), `upgrade-insecure-requests`, plus
1630
+ X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS and Permissions-Policy.
1631
+ - **Nonce per request:** the release build with `secure: true` writes
1632
+ `<!--#echo var="CSP_NONCE" -->` into the nonce attributes and `<meta property="csp-nonce">`
1633
+ (placeholder nonces such as `random-csp-nonce` already in the page are replaced too; v0.32 and
1634
+ earlier wrote `UNIQUE_ID`). Apache fills it by SSI from `UNIQUE_ID` with `@` replaced (a nonce
1635
+ may not hold `@`); Nginx replaces it with `$request_id` through `sub_filter`. The CSP header carries
1636
+ the same value; `index.html` is sent with `Cache-Control: no-store`. `runtime/csp-nonce` gives
1637
+ the nonce to elements Angular adds later.
1638
+ - **Generated vs hand-written:** generated files start with
1639
+ `# Generated by pstack csp from csp-allowlist.json`; `pstack csp` rewrites those and missing
1640
+ ones, and keeps any other file unless `--force`.
1641
+ - **Critical CSS:** Angular's inlined critical CSS loads the stylesheet with an `onload`
1642
+ handler, which the strict `script-src` blocks; new apps set
1643
+ `optimization.styles.inlineCritical: false`, and `pstack csp` warns when a build still inlines
1644
+ it.
1645
+ - **Nginx and a base href:** the generated server block serves the app at `/`; adjust `root` and
1646
+ `location` when it lives under a base href.
1647
+ - **Apache requirements:** mod_rewrite, mod_headers, mod_include, mod_unique_id and mod_setenvif,
1648
+ and `AllowOverride FileInfo Options=IncludesNOEXEC` (or `All`) for the folder — the default
1649
+ `AllowOverride None` ignores the file, and without `Options` rights Apache answers 500.
1650
+ - **Nonce strength:** Nginx's `$request_id` is 16 random bytes per request. Apache's `UNIQUE_ID`
1651
+ is unique but not random per request (a per-process random part plus time and a counter), so
1652
+ someone who sees one response can guess later nonces from the same process; prefer Nginx, or a
1653
+ nonce from your app server, where that matters. A server that sets its own random `UNIQUE_ID` (for
1654
+ example through mod_lua, with mod_unique_id off) is used as is. A missing module fails closed: the header
1655
+ carries `'nonce-(null)'` and the page `(none)`, so scripts are blocked.
1656
+ - **Nginx notes:** needs nginx 1.11+ (`$request_id`) and `include mime.types` in the `http` block;
1657
+ `sub_filter` is skipped when a precompressed `index.html.gz`/`.br` is served (gzip_static).
1658
+ - **Tag managers:** an inline GTM snippet needs the page nonce (the release build adds it to inline
1659
+ scripts); the scripts GTM loads later must be listed in `script-src` and may need more.
1660
+ - **Upgrading from v0.32 or earlier:** the build placeholder changed from `UNIQUE_ID` to
1661
+ `CSP_NONCE`, and earlier generated `.htaccess`/`nginx.conf` files carry no marker, so
1662
+ `pstack csp` treats them as hand-written. Under an Apache `Alias` (URL path differs from the folder),
1663
+ add `RewriteBase /<base href>/`. Run `pstack csp --app=<app> --force` once (after
1664
+ copying any hand-made changes into `csp-allowlist.json`).
1665
+
1666
+ **Importing an existing policy (v0.38.0).** `--import` merges a CSP an app already has into its
1667
+ `csp-allowlist.json`, then renders the server files as usual:
1668
+
1669
+ ```bash
1670
+ pstack csp --app=portal --import=apps/portal/src/.htaccess --dry-run # see what would change
1671
+ pstack csp --app=portal --import=apps/portal/src/.htaccess --force # merge, replace the old file
1672
+ pstack csp --app=portal --import=policy.json # { "script-src": [...], ... }
1673
+ pstack csp --app=portal --import="connect-src https://api.example.com; img-src https://cdn.example.com"
1674
+ ```
1675
+
1676
+ - Sources: a `Content-Security-Policy` header value (inline or in a file), an Apache `.htaccess`
1677
+ (`Header … Content-Security-Policy "…"`) or Nginx config (`add_header …`; Report-Only headers are
1678
+ not read), or JSON — directive → sources, also under `directives` or `suggestedPolicy.directives`.
1679
+ A file path is read relative to the folder you run the command in.
1680
+ - The import is merged into what is there; existing entries are never removed. Imported sources
1681
+ an entry already allows are not added: duplicates (any case) and paths under a listed host
1682
+ (`https://cdn.example.com/x.js` when `https://cdn.example.com` is listed; `*.example.com` covers
1683
+ its subdomains; a host without a scheme covers `https://` only). A config with several CSP
1684
+ headers is merged with a note (a browser enforces each of them).
1685
+ - The report lists what was added (`+`), already allowed (`=`), refused by the strict policy and
1686
+ not taken by the generated policy, each with the reason. Refused / not taken:
1687
+ `'unsafe-inline'`, `'unsafe-eval'`, bare schemes in script/style-src, `http://` hosts, and
1688
+ directives the generated policy does not take (`script-src-elem`, `style-src-elem` — their hosts
1689
+ are listed so you can add them with `--add` — `object-src`, `default-src`, …). Nonces and hashes
1690
+ are skipped: the server adds the nonce per request.
1691
+
1692
+ **Adding an environment later (v0.34.0).** New apps always start with `dev`, `uat` and `prod`.
1693
+ `pstack env` adds another environment to some apps, or all of them, copied from an existing
1694
+ one:
1695
+
1696
+ ```bash
1697
+ pstack env --name=qa --app=portal --api-url=https://qa.example.com/api
1698
+ pstack env --name=sit --app=portal,admin --from=prod --production=false --base-href=/sit/
1699
+ pstack env --name=perf --all
1700
+ ```
1701
+
1702
+ For each app it adds:
1703
+
1704
+ - **Angular/Ionic:** `environments/<app>/environment.<env>.ts` copied from the `--from`
1705
+ environment's file (default `uat`, or `prod` for apps without `uat`). `envName` is set to the
1706
+ new env, api urls are replaced with `--api-url`, and `production` is set when
1707
+ `--production` is given. For apps with a release target, secret fields become
1708
+ `${<APP>_<ENV>_<KEY>}` placeholders (for example `${PORTAL_QA_PASSWORD}`), which the release
1709
+ build fills from CI variables or `.env.local` (a missing one fails the build): in `listed`
1710
+ mode the listed keys, in `all` mode the non-public fields that look sensitive (password, token,
1711
+ key, secret…) or already hold a placeholder. URLs and plain settings are copied. Apps without a
1712
+ release target get the values copied (nothing would fill a placeholder), and nested listed keys
1713
+ are copied with a note. The file goes where the release build reads it:
1714
+ `environments/<envProject>/environment.<env>.ts`.
1715
+ - **Angular `build` and `serve` configurations:** the source build configuration (budgets,
1716
+ optimisation, other file replacements) with the env file swapped.
1717
+ - **Release configuration:** the source one (hardening, obfuscation, SRI, base href) with `env`
1718
+ and `buildConfiguration` set. `--base-href` overrides the base href. The domain lock is not
1719
+ copied: pass `--domains`, or set it later with `pstack encryption --domains`.
1720
+ - **Flutter:** `env/<env>.json` copied (env name and api url updated; values are copied as
1721
+ they are — dart-defines have no placeholders), and `build-web`,
1722
+ `build-android` and `build-ios` configurations copied (`--base-href` on `build-web`).
1723
+ - **npm scripts** (`serve:`/`build:<app>:<env>`, Ionic `:android`/`:ios`, Flutter
1724
+ `:web`/`:apk`/`:ios`), and the AI-assistant block is refreshed.
1725
+
1726
+ `--app` or `--all` is required. Everything is checked first; a new env that already exists, or a
1727
+ missing `--from` configuration, stops the command with every problem listed and nothing
1728
+ written.
1729
+
1730
+ **App generator options (v0.35.0).** `pstack app` gives every new app a dev-server port, a `clean`
1731
+ target and, for Angular/Ionic, the shared assets and styles folders:
1732
+
1733
+ ```bash
1734
+ pstack app --type=angular --name=admin # next free port from 4200
1735
+ pstack app --type=angular --name=admin --port=4300 # explicit port (1024-65535)
1736
+ pstack app --type=angular --name=admin --env-layout=per-env # environment.dev|uat|prod.ts
1737
+ pstack shared --all # wire the shared folders into existing apps
1738
+ nx run admin:clean # or npm run clean:admin
1739
+ ```
1740
+
1741
+ - **Port.** The lowest port from 4200 that no app of the workspace serves on (a serve target
1742
+ without a port counts as 4200), set as `serve.options.port` (Flutter: the `flutter-build`
1743
+ executor's new `port` option, used for `--web-port`). A `--port` another app uses is refused.
1744
+ - **Shared assets and styles.** `libs/shared/assets` and `libs/shared/styles` are created on first
1745
+ use (projects `shared-assets` and `shared-styles`; a workspace that already has `libs/assets` /
1746
+ `libs/styles` uses those, and a `libs/shared` that is itself a library gets `libs/assets` and
1747
+ `libs/styles` instead). New Angular/Ionic apps copy the assets to `assets/shared/`, can
1748
+ `@use 'theme';` (the Sass include path holds the styles folder) and list both projects in
1749
+ `implicitDependencies`. `pstack shared --app=<a,b>|--all` does the same for existing apps.
1750
+ - **`--env-layout=per-env`** (Angular/Ionic): `environments/<app>/environment.{dev,uat,prod}.ts`
1751
+ and a shared `environments/environment.ts` (created when missing) that the app imports; the
1752
+ development, uat and production build configurations replace it with the app's file. The release
1753
+ build reads `environment.dev.ts` for DEV. The default layout is unchanged.
1754
+ - **`clean`** (`@mouryaamit/nx-polystack:clean`) removes `dist/<app root>` and
1755
+ `coverage/<app root>`; Flutter apps also run `flutter clean` (a warning when Flutter is not
1756
+ installed). Only paths below `dist/`, `coverage/` or `tmp/`, or the project's own output
1757
+ folders (`www`, `build`, … under its root), are removed; anything else is refused.
1758
+ - **`pstack update`** (migration `app-clean-and-port`) adds `clean` to apps without one (Angular
1759
+ outputs from the build `outputPath`) and, when several apps serve without a port (all on 4200),
1760
+ keeps 4200 for the first by name and gives the others the next free ports. It does not wire the
1761
+ shared folders.
1762
+
1763
+ **Quality checks (v0.36.0).** Type errors, broken imports and unused imports are caught before
1764
+ review:
1765
+
1766
+ ```bash
1767
+ nx run portal:typecheck # tsc --noEmit -p apps/portal/tsconfig.app.json
1768
+ nx affected -t lint typecheck test build # what CI runs
1769
+ pstack infra --with=none --lint-staged=block # make ESLint block commits again (warn: report only)
1770
+ ```
1771
+
1772
+ - **`typecheck`** on every app and lib with a `tsconfig.app.json` / `tsconfig.lib.json`
1773
+ (`nx:run-commands`, `tsc --noEmit -p …`), cached through nx.json `targetDefaults`. New
1774
+ Angular/Ionic apps and TypeScript libs get it; `pstack infra --with=quality` adds it to every
1775
+ project without one (for example after `pstack migrate`). CI runs it in the affected step.
1776
+ - **ESLint**: `import/no-unresolved` (resolved through `tsconfig.base.json` paths) and
1777
+ `unused-imports/no-unused-imports`, both warnings, in an override of the root `.eslintrc.json`;
1778
+ packages `eslint-plugin-import`, `eslint-import-resolver-typescript` and
1779
+ `eslint-plugin-unused-imports` (the version that matches the workspace's `@typescript-eslint`).
1780
+ - **lint-staged**: new workspaces run ESLint on commit through
1781
+ `tools/scripts/lint-staged-eslint.js` (the workspace ESLint, no npx), which fixes what it can and
1782
+ reports the rest without
1783
+ blocking the commit (Prettier still formats). `pstack infra --lint-staged=block|warn` switches.
1784
+ - **`pstack update`** (migration `quality-checks`) adds the typecheck targets, the nx.json default,
1785
+ the CI step (when the workflow has the standard `nx affected -t lint test build` line) and the
1786
+ ESLint warnings with their packages. It does not change the commit hook. Run
1787
+ `npx nx run-many -t typecheck` once afterwards: libraries are now type-checked as a whole.
1788
+
1789
+ **Session timeout and PII masking libs (v0.37.0).** Two Angular 15 starter libs, Angular and RxJS
1790
+ only (no third-party packages), buildable by default (`--variant=internal|buildable|publishable`):
1791
+
1792
+ ```bash
1793
+ pstack lib --type=session --name=session # @<scope>/shared-session
1794
+ pstack lib --type=pii --name=pii-mask # @<scope>/shared-pii-mask
1795
+ ```
1796
+
1797
+ - **`session`**: `SessionTimeoutService` with `start(loginTime?)`, `stop()`, `extend()`, `state$`
1798
+ (`stopped` / `active` / `warning` / `timedOut`), `warning$` (seconds left), `timeout$` (`idle` or
1799
+ `absolute`, once per session) and `stoppedElsewhere$` (another tab signed out);
1800
+ `SessionTimeoutModule.forRoot({ idleMs, warningMs, absoluteMs })` in the root module; a non-modal
1801
+ `<prefix>-session-warning` component (countdown, focus on its first button, screen-reader
1802
+ announcements at thresholds, `[texts]` for other languages). Tabs share activity, timeouts and
1803
+ logouts (BroadcastChannel, localStorage as fallback; the key includes the app's base path, so two
1804
+ apps on one domain stay apart); a tab waking from sleep checks the others' last activity before
1805
+ timing out. Bad start times are refused and unreadable times end the session (fail closed).
1806
+ Timers run outside Angular's zone; nothing runs during server-side rendering. It never signs
1807
+ anyone out or touches tokens: the app does that on `timeout$` and `stoppedElsewhere$`.
1808
+ - **`pii`**: `maskPii(value, format)`, the `piiMask` pipe and the `[<prefix>PiiMask]` directive
1809
+ (writes text, never HTML). Formats: `pan`, `aadhaar`, `mobile`, `email`, `account`, `card`, `ifsc`
1810
+ (shown as it is); custom formats and the mask character through `PiiMaskModule.forRoot(…)`. A
1811
+ value that does not match its format is masked completely, in any script (Devanagari digits,
1812
+ regional-script names); at most half of a value is ever shown. Display only: stored and sent
1813
+ values are unchanged.
1814
+ - The timing (`session-clock.ts`) and masking (`pii-mask.ts`) logic has no Angular imports, so it
1815
+ can be unit-tested directly.
1816
+
1817
+ **Running:**
1818
+
1819
+ ```bash
1820
+ npx nx run portal:release:dev
1821
+ npx nx run portal:release:uat
1822
+ npx nx run portal:release:prod
1823
+ ```
1824
+
1825
+ ---
1826
+
1827
+ ### `:capacitor` — Capacitor commands for Ionic apps
1828
+
1829
+ Runs `npx cap <command> <platform>` inside the app folder. If the app's `node_modules` is missing it runs
1830
+ `npm install` there first. `sync` and `copy` check that the web build exists (`dist/apps/<project>`, or `webDir`).
1831
+
1832
+ | Option | Description |
1833
+ | ---------- | ----------------------------------------------------------------------------------- |
1834
+ | `command` | `sync`, `open`, `add` or `copy` (set per target: `cap-sync`, `cap-open`, `cap-add`) |
1835
+ | `platform` | `android` or `ios` — pass as `--platform=android` |
1836
+ | `webDir` | Web build output relative to the workspace root (default `dist/apps/<project>`) |
1837
+
1838
+ ```bash
1839
+ npx nx run field-ops:cap-sync --platform=android
1840
+ npx nx run field-ops:cap-open --platform=ios
1841
+ ```
1842
+
1843
+ ---
1844
+
1845
+ ### `:flutter-build` — Flutter build wrapper
1846
+
1847
+ Wraps `flutter build` with `--dart-define-from-file` environment wiring and optional obfuscation.
1848
+
1849
+ ```bash
1850
+ npx nx run mobile:flutter-build:web
1851
+ npx nx run mobile:flutter-build:apk
1852
+ npx nx run mobile:flutter-build:ios
1853
+ ```
1854
+
1855
+ ---
1856
+
1857
+ ### `:flutter-export` — FlutterFlow export
1858
+
1859
+ Exports a FlutterFlow project into the local `apps/<name>/` directory using the FlutterFlow CLI.
1860
+
1861
+ ```bash
1862
+ npx nx run mobile:flutter-export
1863
+ ```
1864
+
1865
+ ---
1866
+
1867
+ ## 8. Helper modules
1868
+
1869
+ Import helpers directly from the package in your own scripts or tools:
1870
+
1871
+ ```typescript
1872
+ import {
1873
+ resolveCiContext,
1874
+ encryptEnvFile,
1875
+ injectBuildMeta,
1876
+ injectCspNonce,
1877
+ injectSri,
1878
+ stripExif,
1879
+ addNpmScripts,
1880
+ addTsPath,
1881
+ generateAngularEnvFiles,
1882
+ mergeNxTargets,
1883
+ backupAndOverwrite,
1884
+ } from '@mouryaamit/nx-polystack';
1885
+ ```
1886
+
1887
+ | Helper | Description |
1888
+ | ---------------------------------------- | ------------------------------------------------------------------------ |
1889
+ | `resolveCiContext()` | Resolves branch, commit SHA, and build number from CI env vars or git |
1890
+ | `encryptEnvFile(file, keys)` | AES-encrypts named keys in an environment TypeScript file |
1891
+ | `injectBuildMeta(distDir, ctx)` | Injects `<meta name="x-build">` into `dist/index.html` |
1892
+ | `injectCspNonce(distDir)` | Replaces nonce placeholders with SSI variables for Apache/Nginx |
1893
+ | `injectSri(distDir, allowlist)` | Adds `integrity=` + `crossorigin=` to local `<script>` and `<link>` tags |
1894
+ | `stripExif(dir)` | Recursively strips EXIF/IPTC/XMP metadata from images |
1895
+ | `addNpmScripts(tree, scripts)` | Adds entries to root `package.json` scripts (Nx Tree mutator) |
1896
+ | `addTsPath(tree, alias, path)` | Adds a path alias to `tsconfig.base.json` (Nx Tree mutator) |
1897
+ | `generateAngularEnvFiles(tree, name)` | Creates `environments/<name>/environment*.ts` stubs |
1898
+ | `mergeNxTargets(tree, project, targets)` | Merges targets into a project's `project.json` |
1899
+ | `backupAndOverwrite(src, dest)` | Creates a `.bak` copy of a file then overwrites it |
1900
+
1901
+ ---
1902
+
1903
+ ## 9. Release packaging
1904
+
1905
+ Releases are published to npm from this repository's `Publish` workflow when a `vX.Y.Z` tag is pushed.
1906
+
1907
+ ---
1908
+
1909
+ ## 10. Troubleshooting
1910
+
1911
+ ### `pstack: command not found` after global install
1912
+
1913
+ Check that the npm global bin directory is in your `PATH`:
1914
+
1915
+ ```bash
1916
+ npm config get prefix # e.g. /usr/local
1917
+ # Ensure /usr/local/bin is in PATH
1918
+ ```
1919
+
1920
+ ### `Error: no nx.json found in the current directory`
1921
+
1922
+ The `pstack app` command must be run from the root of an existing Nx workspace. Run `pstack preset` first
1923
+ if you are starting from scratch.
1924
+
1925
+ ### Generator changes nothing (`Nothing to generate.`)
1926
+
1927
+ The target project path may already exist. Pass `--force` via Nx:
1928
+
1929
+ ```bash
1930
+ npx nx g @mouryaamit/nx-polystack:app --type=angular --name=portal --force
1931
+ ```
1932
+
1933
+ The `pstack` CLI does not support `--force` directly — use the Nx generator form for this.
1934
+
1935
+ ### `Error: env is required` from the `:build` executor
1936
+
1937
+ The `:build` executor expects `env` to be set via an Nx configuration, not as a top-level option.
1938
+ Ensure your `project.json` has `configurations` with `"env": "DEV|UAT|PROD"`:
1939
+
1940
+ ```jsonc
1941
+ "configurations": {
1942
+ "dev": { "env": "DEV" }
1943
+ }
1944
+ ```
1945
+
1946
+ Then run with: `npx nx run <project>:build:dev`
1947
+
1948
+ ### Shebang missing on `bin/cli.js`
1949
+
1950
+ Re-run `npm run build`. The build script automatically adds `#!/usr/bin/env node`
1951
+ if it was stripped by the TypeScript compiler.
1952
+
1953
+ ### Version mismatch between `pstack --version` and installed package
1954
+
1955
+ `pstack --version` reads the `version` field from the bundled `package.json` at runtime. If the
1956
+ version shown differs from what was installed, you may have a stale global install:
1957
+
1958
+ ```bash
1959
+ npm i -g @mouryaamit/nx-polystack@latest
1960
+ ```
1961
+
1962
+ Inside a workspace whose local plugin version differs from the global CLI, `pstack -v` prints the global
1963
+ version followed by `workspace plugin: X`.
1964
+
1965
+ ---
1966
+
1967
+ _See also:_
1968
+ _`README.md` — quick-start and plugin architecture_