@lenne.tech/ng-base 18.1.3 → 22.0.0

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 (416) hide show
  1. package/CLAUDE.md +55 -0
  2. package/LICENSE +2 -2
  3. package/README.md +237 -44
  4. package/fesm2022/lenne.tech-ng-base-ai.mjs +767 -0
  5. package/fesm2022/lenne.tech-ng-base-ai.mjs.map +1 -0
  6. package/fesm2022/lenne.tech-ng-base-auth-provide.mjs +939 -0
  7. package/fesm2022/lenne.tech-ng-base-auth-provide.mjs.map +1 -0
  8. package/fesm2022/lenne.tech-ng-base-auth.mjs +454 -0
  9. package/fesm2022/lenne.tech-ng-base-auth.mjs.map +1 -0
  10. package/fesm2022/lenne.tech-ng-base-bug-bug-report-dialog-BRzVmKJr.mjs +825 -0
  11. package/fesm2022/lenne.tech-ng-base-bug-bug-report-dialog-BRzVmKJr.mjs.map +1 -0
  12. package/fesm2022/lenne.tech-ng-base-bug-bug-report-service-DWoTb_iw.mjs +351 -0
  13. package/fesm2022/lenne.tech-ng-base-bug-bug-report-service-DWoTb_iw.mjs.map +1 -0
  14. package/fesm2022/lenne.tech-ng-base-bug-capture-engine-TkjMDdqj.mjs +1046 -0
  15. package/fesm2022/lenne.tech-ng-base-bug-capture-engine-TkjMDdqj.mjs.map +1 -0
  16. package/fesm2022/lenne.tech-ng-base-bug-constants-Brm2KGHi.mjs +4 -0
  17. package/fesm2022/lenne.tech-ng-base-bug-constants-Brm2KGHi.mjs.map +1 -0
  18. package/fesm2022/lenne.tech-ng-base-bug-messages-BsP4fRQU.mjs +179 -0
  19. package/fesm2022/lenne.tech-ng-base-bug-messages-BsP4fRQU.mjs.map +1 -0
  20. package/fesm2022/lenne.tech-ng-base-bug-provide.mjs +26 -0
  21. package/fesm2022/lenne.tech-ng-base-bug-provide.mjs.map +1 -0
  22. package/fesm2022/lenne.tech-ng-base-bug-report-Tzlhe1Cm.mjs +62 -0
  23. package/fesm2022/lenne.tech-ng-base-bug-report-Tzlhe1Cm.mjs.map +1 -0
  24. package/fesm2022/lenne.tech-ng-base-bug-server.mjs +818 -0
  25. package/fesm2022/lenne.tech-ng-base-bug-server.mjs.map +1 -0
  26. package/fesm2022/lenne.tech-ng-base-bug.mjs +196 -0
  27. package/fesm2022/lenne.tech-ng-base-bug.mjs.map +1 -0
  28. package/fesm2022/lenne.tech-ng-base-files-ui.mjs +445 -0
  29. package/fesm2022/lenne.tech-ng-base-files-ui.mjs.map +1 -0
  30. package/fesm2022/lenne.tech-ng-base-files.mjs +474 -0
  31. package/fesm2022/lenne.tech-ng-base-files.mjs.map +1 -0
  32. package/fesm2022/lenne.tech-ng-base-server.mjs +408 -0
  33. package/fesm2022/lenne.tech-ng-base-server.mjs.map +1 -0
  34. package/fesm2022/lenne.tech-ng-base-share.mjs +76 -0
  35. package/fesm2022/lenne.tech-ng-base-share.mjs.map +1 -0
  36. package/fesm2022/lenne.tech-ng-base-sync.mjs +1096 -0
  37. package/fesm2022/lenne.tech-ng-base-sync.mjs.map +1 -0
  38. package/fesm2022/lenne.tech-ng-base-testing.mjs +171 -0
  39. package/fesm2022/lenne.tech-ng-base-testing.mjs.map +1 -0
  40. package/fesm2022/lenne.tech-ng-base-ui-provide.mjs +124 -0
  41. package/fesm2022/lenne.tech-ng-base-ui-provide.mjs.map +1 -0
  42. package/fesm2022/lenne.tech-ng-base-ui.mjs +34611 -0
  43. package/fesm2022/lenne.tech-ng-base-ui.mjs.map +1 -0
  44. package/fesm2022/lenne.tech-ng-base-utils.mjs +287 -0
  45. package/fesm2022/lenne.tech-ng-base-utils.mjs.map +1 -0
  46. package/fesm2022/lenne.tech-ng-base.mjs +615 -910
  47. package/fesm2022/lenne.tech-ng-base.mjs.map +1 -1
  48. package/i18n/auth/de.json +17 -0
  49. package/i18n/auth/en.json +17 -0
  50. package/i18n/bug/de.json +85 -0
  51. package/i18n/bug/en.json +85 -0
  52. package/i18n/de.json +8 -0
  53. package/i18n/en.json +8 -0
  54. package/i18n/files/de.json +27 -0
  55. package/i18n/files/en.json +27 -0
  56. package/i18n/share/de.json +8 -0
  57. package/i18n/share/en.json +8 -0
  58. package/i18n/ui/de.json +38 -0
  59. package/i18n/ui/en.json +38 -0
  60. package/package.json +127 -58
  61. package/types/lenne.tech-ng-base-ai.d.ts +830 -0
  62. package/types/lenne.tech-ng-base-auth-provide.d.ts +603 -0
  63. package/types/lenne.tech-ng-base-auth.d.ts +320 -0
  64. package/types/lenne.tech-ng-base-bug-provide.d.ts +272 -0
  65. package/types/lenne.tech-ng-base-bug-rolldown-runtime-C25Le4-w.d.ts +1 -0
  66. package/types/lenne.tech-ng-base-bug-server.d.ts +316 -0
  67. package/types/lenne.tech-ng-base-bug.d.ts +202 -0
  68. package/types/lenne.tech-ng-base-files-ui.d.ts +116 -0
  69. package/types/lenne.tech-ng-base-files.d.ts +288 -0
  70. package/types/lenne.tech-ng-base-server.d.ts +262 -0
  71. package/types/lenne.tech-ng-base-share.d.ts +21 -0
  72. package/types/lenne.tech-ng-base-sync.d.ts +380 -0
  73. package/types/lenne.tech-ng-base-testing.d.ts +327 -0
  74. package/types/lenne.tech-ng-base-ui-provide.d.ts +65 -0
  75. package/types/lenne.tech-ng-base-ui.d.ts +7732 -0
  76. package/types/lenne.tech-ng-base-utils.d.ts +150 -0
  77. package/types/lenne.tech-ng-base.d.ts +503 -0
  78. package/ui/styles/components/accordion.css +3 -0
  79. package/ui/styles/components/alert-dialog.css +4 -0
  80. package/ui/styles/components/alert.css +3 -0
  81. package/ui/styles/components/aspect-ratio.css +3 -0
  82. package/ui/styles/components/attachment.css +4 -0
  83. package/ui/styles/components/autocomplete.css +4 -0
  84. package/ui/styles/components/avatar.css +3 -0
  85. package/ui/styles/components/badge.css +3 -0
  86. package/ui/styles/components/breadcrumb.css +3 -0
  87. package/ui/styles/components/bubble.css +3 -0
  88. package/ui/styles/components/button-group.css +3 -0
  89. package/ui/styles/components/button.css +3 -0
  90. package/ui/styles/components/calendar.css +5 -0
  91. package/ui/styles/components/card.css +3 -0
  92. package/ui/styles/components/checkbox.css +3 -0
  93. package/ui/styles/components/code-block.css +4 -0
  94. package/ui/styles/components/collapsible.css +3 -0
  95. package/ui/styles/components/combobox.css +5 -0
  96. package/ui/styles/components/command.css +5 -0
  97. package/ui/styles/components/context-menu.css +3 -0
  98. package/ui/styles/components/date-picker.css +7 -0
  99. package/ui/styles/components/dialog.css +4 -0
  100. package/ui/styles/components/drawer.css +3 -0
  101. package/ui/styles/components/dropdown-menu.css +3 -0
  102. package/ui/styles/components/empty.css +3 -0
  103. package/ui/styles/components/field.css +5 -0
  104. package/ui/styles/components/hover-card.css +3 -0
  105. package/ui/styles/components/index.css +91 -0
  106. package/ui/styles/components/input-group.css +6 -0
  107. package/ui/styles/components/input-otp.css +3 -0
  108. package/ui/styles/components/input.css +3 -0
  109. package/ui/styles/components/item.css +4 -0
  110. package/ui/styles/components/kbd.css +3 -0
  111. package/ui/styles/components/label.css +3 -0
  112. package/ui/styles/components/lt-breadcrumb.css +3 -0
  113. package/ui/styles/components/lt-bug-attachments.css +5 -0
  114. package/ui/styles/components/lt-bug-journey-timeline.css +5 -0
  115. package/ui/styles/components/lt-bug-report-dialog.css +15 -0
  116. package/ui/styles/components/lt-bug-report.css +4 -0
  117. package/ui/styles/components/lt-color-mode-button.css +3 -0
  118. package/ui/styles/components/lt-confirm-dialog.css +4 -0
  119. package/ui/styles/components/lt-data-view.css +5 -0
  120. package/ui/styles/components/lt-date-picker.css +3 -0
  121. package/ui/styles/components/lt-date-time-picker.css +5 -0
  122. package/ui/styles/components/lt-enter-action.css +2 -0
  123. package/ui/styles/components/lt-footer.css +3 -0
  124. package/ui/styles/components/lt-form-field.css +4 -0
  125. package/ui/styles/components/lt-header.css +5 -0
  126. package/ui/styles/components/lt-imports.css +21 -0
  127. package/ui/styles/components/lt-navigation-menu.css +3 -0
  128. package/ui/styles/components/lt-notice.css +3 -0
  129. package/ui/styles/components/lt-overlay-defaults.css +3 -0
  130. package/ui/styles/components/lt-page-card.css +3 -0
  131. package/ui/styles/components/lt-page-title.css +2 -0
  132. package/ui/styles/components/lt-password-input.css +4 -0
  133. package/ui/styles/components/lt-readonly-field.css +2 -0
  134. package/ui/styles/components/lt-select.css +4 -0
  135. package/ui/styles/components/lt-text-field.css +5 -0
  136. package/ui/styles/components/lt-toolbar-item.css +2 -0
  137. package/ui/styles/components/lt-toolbar.css +3 -0
  138. package/ui/styles/components/lt-tus-upload-component.css +5 -0
  139. package/ui/styles/components/marker.css +3 -0
  140. package/ui/styles/components/menubar.css +3 -0
  141. package/ui/styles/components/message-scroller.css +4 -0
  142. package/ui/styles/components/message.css +3 -0
  143. package/ui/styles/components/native-select.css +3 -0
  144. package/ui/styles/components/navigation-menu.css +3 -0
  145. package/ui/styles/components/pagination.css +4 -0
  146. package/ui/styles/components/popover.css +3 -0
  147. package/ui/styles/components/progress.css +3 -0
  148. package/ui/styles/components/questionnaire.css +4 -0
  149. package/ui/styles/components/radio-group.css +3 -0
  150. package/ui/styles/components/resizable.css +3 -0
  151. package/ui/styles/components/select.css +3 -0
  152. package/ui/styles/components/separator.css +3 -0
  153. package/ui/styles/components/sheet.css +4 -0
  154. package/ui/styles/components/sidebar.css +9 -0
  155. package/ui/styles/components/skeleton.css +3 -0
  156. package/ui/styles/components/slider.css +3 -0
  157. package/ui/styles/components/sonner.css +4 -0
  158. package/ui/styles/components/spinner.css +3 -0
  159. package/ui/styles/components/switch.css +3 -0
  160. package/ui/styles/components/table.css +3 -0
  161. package/ui/styles/components/tabs.css +4 -0
  162. package/ui/styles/components/textarea.css +3 -0
  163. package/ui/styles/components/toggle-group.css +4 -0
  164. package/ui/styles/components/toggle.css +3 -0
  165. package/ui/styles/components/tooltip.css +3 -0
  166. package/ui/styles/components/trace.css +3 -0
  167. package/ui/styles/components/typography.css +3 -0
  168. package/ui/styles/components/utils.css +2 -0
  169. package/ui/styles/core.css +137 -0
  170. package/ui/styles/palette.css +94 -0
  171. package/ui/styles/theme.css +14 -0
  172. package/ui/styles/transitions.css +131 -0
  173. package/base-cms/index.d.ts +0 -5
  174. package/base-cms/interfaces/base-cms-module-config.interface.d.ts +0 -16
  175. package/base-cms/pages/base-cms/base-cms.component.d.ts +0 -92
  176. package/base-cms/public-api.d.ts +0 -5
  177. package/base-components/components/breadcrumb/breadcrumb.component.d.ts +0 -10
  178. package/base-components/components/change-password/change-password.component.d.ts +0 -24
  179. package/base-components/components/checkbox/checkbox.component.d.ts +0 -12
  180. package/base-components/components/delete-account/delete-account.component.d.ts +0 -15
  181. package/base-components/components/fab-button/fab-button.component.d.ts +0 -16
  182. package/base-components/components/input/input.component.d.ts +0 -27
  183. package/base-components/components/loading-bar/loading-bar.component.d.ts +0 -17
  184. package/base-components/components/model-form/model-form-base.component.d.ts +0 -64
  185. package/base-components/components/model-form/model-form.component.d.ts +0 -139
  186. package/base-components/components/model-form-sub/model-form-sub.component.d.ts +0 -56
  187. package/base-components/components/model-table/model-table.component.d.ts +0 -115
  188. package/base-components/components/refence-input/refence-input.component.d.ts +0 -84
  189. package/base-components/components/select/select.component.d.ts +0 -25
  190. package/base-components/components/skeleton-loader/skeleton-loader.component.d.ts +0 -10
  191. package/base-components/components/tags/tags.component.d.ts +0 -60
  192. package/base-components/components/textarea/textarea.component.d.ts +0 -21
  193. package/base-components/components/toast/toast.component.d.ts +0 -19
  194. package/base-components/components/upload-image/upload-image.component.d.ts +0 -111
  195. package/base-components/directives/back-button.directive.d.ts +0 -9
  196. package/base-components/directives/context-menu.directive.d.ts +0 -22
  197. package/base-components/directives/sort.directive.d.ts +0 -15
  198. package/base-components/directives/stop-propagation.directive.d.ts +0 -10
  199. package/base-components/index.d.ts +0 -5
  200. package/base-components/pipes/ellipses.pipe.d.ts +0 -10
  201. package/base-components/public-api.d.ts +0 -26
  202. package/base-prototype/index.d.ts +0 -5
  203. package/base-prototype/pages/email-verification/email-verification.component.d.ts +0 -18
  204. package/base-prototype/pages/forgot-password/forgot-password.component.d.ts +0 -26
  205. package/base-prototype/pages/login/login.component.d.ts +0 -33
  206. package/base-prototype/pages/profile/profile.component.d.ts +0 -24
  207. package/base-prototype/pages/register/register.component.d.ts +0 -31
  208. package/base-prototype/pages/set-password/set-password.component.d.ts +0 -29
  209. package/base-prototype/public-api.d.ts +0 -9
  210. package/esm2022/base-cms/interfaces/base-cms-module-config.interface.mjs +0 -3
  211. package/esm2022/base-cms/lenne.tech-ng-base-base-cms.mjs +0 -5
  212. package/esm2022/base-cms/pages/base-cms/base-cms.component.mjs +0 -238
  213. package/esm2022/base-cms/public-api.mjs +0 -8
  214. package/esm2022/base-components/components/breadcrumb/breadcrumb.component.mjs +0 -23
  215. package/esm2022/base-components/components/change-password/change-password.component.mjs +0 -97
  216. package/esm2022/base-components/components/checkbox/checkbox.component.mjs +0 -38
  217. package/esm2022/base-components/components/delete-account/delete-account.component.mjs +0 -59
  218. package/esm2022/base-components/components/fab-button/fab-button.component.mjs +0 -24
  219. package/esm2022/base-components/components/input/input.component.mjs +0 -75
  220. package/esm2022/base-components/components/loading-bar/loading-bar.component.mjs +0 -37
  221. package/esm2022/base-components/components/model-form/model-form-base.component.mjs +0 -145
  222. package/esm2022/base-components/components/model-form/model-form.component.mjs +0 -591
  223. package/esm2022/base-components/components/model-form-sub/model-form-sub.component.mjs +0 -117
  224. package/esm2022/base-components/components/model-table/model-table.component.mjs +0 -478
  225. package/esm2022/base-components/components/refence-input/refence-input.component.mjs +0 -278
  226. package/esm2022/base-components/components/select/select.component.mjs +0 -62
  227. package/esm2022/base-components/components/skeleton-loader/skeleton-loader.component.mjs +0 -33
  228. package/esm2022/base-components/components/tags/tags.component.mjs +0 -227
  229. package/esm2022/base-components/components/textarea/textarea.component.mjs +0 -79
  230. package/esm2022/base-components/components/toast/toast.component.mjs +0 -69
  231. package/esm2022/base-components/components/upload-image/upload-image.component.mjs +0 -346
  232. package/esm2022/base-components/directives/back-button.directive.mjs +0 -25
  233. package/esm2022/base-components/directives/context-menu.directive.mjs +0 -112
  234. package/esm2022/base-components/directives/sort.directive.mjs +0 -61
  235. package/esm2022/base-components/directives/stop-propagation.directive.mjs +0 -24
  236. package/esm2022/base-components/lenne.tech-ng-base-base-components.mjs +0 -5
  237. package/esm2022/base-components/pipes/ellipses.pipe.mjs +0 -23
  238. package/esm2022/base-components/public-api.mjs +0 -30
  239. package/esm2022/base-prototype/lenne.tech-ng-base-base-prototype.mjs +0 -5
  240. package/esm2022/base-prototype/pages/email-verification/email-verification.component.mjs +0 -60
  241. package/esm2022/base-prototype/pages/forgot-password/forgot-password.component.mjs +0 -78
  242. package/esm2022/base-prototype/pages/login/login.component.mjs +0 -114
  243. package/esm2022/base-prototype/pages/profile/profile.component.mjs +0 -87
  244. package/esm2022/base-prototype/pages/register/register.component.mjs +0 -100
  245. package/esm2022/base-prototype/pages/set-password/set-password.component.mjs +0 -91
  246. package/esm2022/base-prototype/public-api.mjs +0 -11
  247. package/esm2022/lenne.tech-ng-base.mjs +0 -5
  248. package/esm2022/public-api.mjs +0 -25
  249. package/esm2022/shared/classes/auth.class.mjs +0 -14
  250. package/esm2022/shared/classes/basic-user.class.mjs +0 -49
  251. package/esm2022/shared/classes/graphql-enum.class.mjs +0 -10
  252. package/esm2022/shared/classes/graphql-meta.class.mjs +0 -345
  253. package/esm2022/shared/classes/graphql-type.class.mjs +0 -14
  254. package/esm2022/shared/classes/helper.class.mjs +0 -307
  255. package/esm2022/shared/classes/sort.class.mjs +0 -38
  256. package/esm2022/shared/classes/standard.class.mjs +0 -40
  257. package/esm2022/shared/decorators/debounce.decorator.mjs +0 -12
  258. package/esm2022/shared/enums/comparison-operator.enum.mjs +0 -16
  259. package/esm2022/shared/enums/graphql-request-type.enum.mjs +0 -10
  260. package/esm2022/shared/enums/logical-operator.enum.mjs +0 -10
  261. package/esm2022/shared/enums/skeleton-type.enum.mjs +0 -7
  262. package/esm2022/shared/enums/sort-order.enum.mjs +0 -6
  263. package/esm2022/shared/enums/toast-type.enum.mjs +0 -8
  264. package/esm2022/shared/functions/ws-client.function.mjs +0 -39
  265. package/esm2022/shared/interfaces/base-module-config.interface.mjs +0 -3
  266. package/esm2022/shared/interfaces/breadcrumb.interface.mjs +0 -2
  267. package/esm2022/shared/interfaces/can-component-deactivate.interface.mjs +0 -2
  268. package/esm2022/shared/interfaces/cms-enum-values.interface.mjs +0 -2
  269. package/esm2022/shared/interfaces/cms-field-config.interface.mjs +0 -2
  270. package/esm2022/shared/interfaces/cms-model-config.interface.mjs +0 -2
  271. package/esm2022/shared/interfaces/cms-table-field.interface.mjs +0 -2
  272. package/esm2022/shared/interfaces/combined-filter-input.interface.mjs +0 -2
  273. package/esm2022/shared/interfaces/compress-options.interface.mjs +0 -2
  274. package/esm2022/shared/interfaces/cropping-options.interface.mjs +0 -2
  275. package/esm2022/shared/interfaces/field-object.interface.mjs +0 -2
  276. package/esm2022/shared/interfaces/field.interface.mjs +0 -2
  277. package/esm2022/shared/interfaces/filter-input.interface.mjs +0 -2
  278. package/esm2022/shared/interfaces/find-args.interface.mjs +0 -2
  279. package/esm2022/shared/interfaces/graphql-crud-type.interface.mjs +0 -2
  280. package/esm2022/shared/interfaces/graphql-fields-object.interface.mjs +0 -2
  281. package/esm2022/shared/interfaces/graphql-options.interface.mjs +0 -2
  282. package/esm2022/shared/interfaces/graphql-plus-options.interfacen.mjs +0 -2
  283. package/esm2022/shared/interfaces/graphql-type-collection.interface.mjs +0 -2
  284. package/esm2022/shared/interfaces/login-config.interface.mjs +0 -2
  285. package/esm2022/shared/interfaces/register-config.interface.mjs +0 -2
  286. package/esm2022/shared/interfaces/single-filter-input.interface.mjs +0 -2
  287. package/esm2022/shared/interfaces/sort-input.interface.mjs +0 -2
  288. package/esm2022/shared/interfaces/time-components.interface.mjs +0 -2
  289. package/esm2022/shared/interfaces/toast.interface.mjs +0 -2
  290. package/esm2022/shared/lenne.tech-ng-base-shared.mjs +0 -5
  291. package/esm2022/shared/public-api.mjs +0 -74
  292. package/esm2022/shared/services/auth.service.mjs +0 -152
  293. package/esm2022/shared/services/breadcrumb.service.mjs +0 -69
  294. package/esm2022/shared/services/cms.service.mjs +0 -82
  295. package/esm2022/shared/services/file.service.mjs +0 -86
  296. package/esm2022/shared/services/forms.service.mjs +0 -61
  297. package/esm2022/shared/services/graphql-meta.service.mjs +0 -132
  298. package/esm2022/shared/services/graphql-plus.service.mjs +0 -93
  299. package/esm2022/shared/services/graphql.service.mjs +0 -510
  300. package/esm2022/shared/services/image.service.mjs +0 -102
  301. package/esm2022/shared/services/loader.service.mjs +0 -78
  302. package/esm2022/shared/services/navigation.service.mjs +0 -38
  303. package/esm2022/shared/services/scroll.service.mjs +0 -207
  304. package/esm2022/shared/services/storage.service.mjs +0 -149
  305. package/esm2022/shared/services/toast.service.mjs +0 -39
  306. package/esm2022/shared/services/user.service.mjs +0 -160
  307. package/esm2022/shared/services/ws.service.mjs +0 -17
  308. package/esm2022/shared/types/graphql-fields.type.mjs +0 -2
  309. package/esm2022/shared/types/storage.type.mjs +0 -2
  310. package/esm2022/shared/validators/email.validator.mjs +0 -7
  311. package/esm2022/shared/validators/match.validator.mjs +0 -22
  312. package/esm2022/shared/validators/secure-password.validator.mjs +0 -7
  313. package/esm2022/src/base.module.mjs +0 -64
  314. package/esm2022/src/decorators/auto-unsubscribe.decorator.mjs +0 -23
  315. package/esm2022/src/directives/lazy-load.directive.mjs +0 -48
  316. package/esm2022/src/directives/match-height.directive.mjs +0 -92
  317. package/esm2022/src/directives/resizable.directive.mjs +0 -92
  318. package/esm2022/src/factories/apollo-options.factory.mjs +0 -108
  319. package/esm2022/src/functions/extract-files.function.mjs +0 -87
  320. package/esm2022/src/guards/auth.guard.mjs +0 -91
  321. package/esm2022/src/guards/can-deactivate.guard.mjs +0 -16
  322. package/esm2022/src/guards/logout.guard.mjs +0 -34
  323. package/esm2022/src/pipes/date-ago.pipe.mjs +0 -64
  324. package/esm2022/src/pipes/safe-html.pipe.mjs +0 -22
  325. package/esm2022/src/services/fullscreen.service.mjs +0 -51
  326. package/esm2022/src/services/seo.service.mjs +0 -117
  327. package/esm2022/src/services/theme.service.mjs +0 -44
  328. package/fesm2022/lenne.tech-ng-base-base-cms.mjs +0 -251
  329. package/fesm2022/lenne.tech-ng-base-base-cms.mjs.map +0 -1
  330. package/fesm2022/lenne.tech-ng-base-base-components.mjs +0 -2917
  331. package/fesm2022/lenne.tech-ng-base-base-components.mjs.map +0 -1
  332. package/fesm2022/lenne.tech-ng-base-base-prototype.mjs +0 -505
  333. package/fesm2022/lenne.tech-ng-base-base-prototype.mjs.map +0 -1
  334. package/fesm2022/lenne.tech-ng-base-shared.mjs +0 -2863
  335. package/fesm2022/lenne.tech-ng-base-shared.mjs.map +0 -1
  336. package/index.d.ts +0 -5
  337. package/public-api.d.ts +0 -17
  338. package/shared/classes/auth.class.d.ts +0 -10
  339. package/shared/classes/basic-user.class.d.ts +0 -27
  340. package/shared/classes/graphql-enum.class.d.ts +0 -7
  341. package/shared/classes/graphql-meta.class.d.ts +0 -66
  342. package/shared/classes/graphql-type.class.d.ts +0 -13
  343. package/shared/classes/helper.class.d.ts +0 -99
  344. package/shared/classes/sort.class.d.ts +0 -12
  345. package/shared/classes/standard.class.d.ts +0 -32
  346. package/shared/decorators/debounce.decorator.d.ts +0 -1
  347. package/shared/enums/comparison-operator.enum.d.ts +0 -14
  348. package/shared/enums/graphql-request-type.enum.d.ts +0 -8
  349. package/shared/enums/logical-operator.enum.d.ts +0 -8
  350. package/shared/enums/skeleton-type.enum.d.ts +0 -5
  351. package/shared/enums/sort-order.enum.d.ts +0 -4
  352. package/shared/enums/toast-type.enum.d.ts +0 -6
  353. package/shared/functions/ws-client.function.d.ts +0 -5
  354. package/shared/index.d.ts +0 -5
  355. package/shared/interfaces/base-module-config.interface.d.ts +0 -61
  356. package/shared/interfaces/breadcrumb.interface.d.ts +0 -4
  357. package/shared/interfaces/can-component-deactivate.interface.d.ts +0 -7
  358. package/shared/interfaces/cms-enum-values.interface.d.ts +0 -4
  359. package/shared/interfaces/cms-field-config.interface.d.ts +0 -45
  360. package/shared/interfaces/cms-model-config.interface.d.ts +0 -14
  361. package/shared/interfaces/cms-table-field.interface.d.ts +0 -10
  362. package/shared/interfaces/combined-filter-input.interface.d.ts +0 -9
  363. package/shared/interfaces/compress-options.interface.d.ts +0 -15
  364. package/shared/interfaces/cropping-options.interface.d.ts +0 -12
  365. package/shared/interfaces/field-object.interface.d.ts +0 -6
  366. package/shared/interfaces/field.interface.d.ts +0 -5
  367. package/shared/interfaces/filter-input.interface.d.ts +0 -9
  368. package/shared/interfaces/find-args.interface.d.ts +0 -11
  369. package/shared/interfaces/graphql-crud-type.interface.d.ts +0 -7
  370. package/shared/interfaces/graphql-fields-object.interface.d.ts +0 -6
  371. package/shared/interfaces/graphql-options.interface.d.ts +0 -11
  372. package/shared/interfaces/graphql-plus-options.interfacen.d.ts +0 -9
  373. package/shared/interfaces/graphql-type-collection.interface.d.ts +0 -7
  374. package/shared/interfaces/login-config.interface.d.ts +0 -6
  375. package/shared/interfaces/register-config.interface.d.ts +0 -4
  376. package/shared/interfaces/single-filter-input.interface.d.ts +0 -11
  377. package/shared/interfaces/sort-input.interface.d.ts +0 -5
  378. package/shared/interfaces/time-components.interface.d.ts +0 -6
  379. package/shared/interfaces/toast.interface.d.ts +0 -8
  380. package/shared/public-api.d.ts +0 -65
  381. package/shared/services/auth.service.d.ts +0 -44
  382. package/shared/services/breadcrumb.service.d.ts +0 -32
  383. package/shared/services/cms.service.d.ts +0 -27
  384. package/shared/services/file.service.d.ts +0 -22
  385. package/shared/services/forms.service.d.ts +0 -14
  386. package/shared/services/graphql-meta.service.d.ts +0 -45
  387. package/shared/services/graphql-plus.service.d.ts +0 -27
  388. package/shared/services/graphql.service.d.ts +0 -71
  389. package/shared/services/image.service.d.ts +0 -27
  390. package/shared/services/loader.service.d.ts +0 -32
  391. package/shared/services/navigation.service.d.ts +0 -15
  392. package/shared/services/scroll.service.d.ts +0 -85
  393. package/shared/services/storage.service.d.ts +0 -49
  394. package/shared/services/toast.service.d.ts +0 -15
  395. package/shared/services/user.service.d.ts +0 -77
  396. package/shared/services/ws.service.d.ts +0 -8
  397. package/shared/types/graphql-fields.type.d.ts +0 -5
  398. package/shared/types/storage.type.d.ts +0 -4
  399. package/shared/validators/email.validator.d.ts +0 -1
  400. package/shared/validators/match.validator.d.ts +0 -4
  401. package/shared/validators/secure-password.validator.d.ts +0 -1
  402. package/src/base.module.d.ts +0 -16
  403. package/src/decorators/auto-unsubscribe.decorator.d.ts +0 -5
  404. package/src/directives/lazy-load.directive.d.ts +0 -17
  405. package/src/directives/match-height.directive.d.ts +0 -20
  406. package/src/directives/resizable.directive.d.ts +0 -26
  407. package/src/factories/apollo-options.factory.d.ts +0 -16
  408. package/src/functions/extract-files.function.d.ts +0 -15
  409. package/src/guards/auth.guard.d.ts +0 -27
  410. package/src/guards/can-deactivate.guard.d.ts +0 -10
  411. package/src/guards/logout.guard.d.ts +0 -16
  412. package/src/pipes/date-ago.pipe.d.ts +0 -34
  413. package/src/pipes/safe-html.pipe.d.ts +0 -13
  414. package/src/services/fullscreen.service.d.ts +0 -18
  415. package/src/services/seo.service.d.ts +0 -61
  416. package/src/services/theme.service.d.ts +0 -17
@@ -0,0 +1,408 @@
1
+ import { writeResponseToNodeResponse } from "@angular/ssr/node";
2
+ import { LT_SERVER_RUNTIME_CONFIG, injectLtRuntimeConfigScript } from "@lenne.tech/ng-base";
3
+ import { makeEnvironmentProviders } from "@angular/core";
4
+ import { Readable, pipeline } from "node:stream";
5
+ const SECURITY_TXT_PATH = "/.well-known/security.txt";
6
+ const SECURITY_TXT_DEFAULT_CONTACT = "mailto:security@lenne.tech";
7
+ const SECURITY_TXT_DEFAULT_LANGUAGES = ["de", "en"];
8
+ const SECURITY_TXT_DEFAULT_VALID_DAYS = 180;
9
+ const SECURITY_TXT_MAX_VALID_DAYS = 365;
10
+ const DAY_MS = 864e5;
11
+ const CONTACT_URI = /^(?:mailto:|tel:|https:\/\/)\S/i;
12
+ function isSingleToken(value) {
13
+ return typeof value === "string" && value.length > 0 && !/\s/.test(value);
14
+ }
15
+ function normalizeSecurityTxtContacts(contact) {
16
+ return (Array.isArray(contact) ? contact : [contact]).map((value) => typeof value === "string" ? value.trim() : value).filter(isSingleToken).filter((value) => CONTACT_URI.test(value));
17
+ }
18
+ function normalizeSecurityTxtList(value) {
19
+ return (typeof value === "string" ? value.split(",") : Array.isArray(value) ? value : []).map((entry) => typeof entry === "string" ? entry.trim() : entry).filter(isSingleToken);
20
+ }
21
+ function normalizeSecurityTxtValidDays(validDays) {
22
+ const days = Number(validDays);
23
+ if (!Number.isFinite(days) || days < 1) return 180;
24
+ return Math.min(Math.floor(days), SECURITY_TXT_MAX_VALID_DAYS);
25
+ }
26
+ function toSecurityTxtOrigin(url) {
27
+ if (!url) return;
28
+ try {
29
+ const parsed = new URL(url);
30
+ return parsed.protocol === "https:" || parsed.protocol === "http:" ? parsed.origin : void 0;
31
+ } catch {
32
+ return;
33
+ }
34
+ }
35
+ function allowedRequestOrigin(host, allowedHosts) {
36
+ const name = host?.trim().toLowerCase();
37
+ const allowed = allowedHosts.map((entry) => entry.trim().toLowerCase());
38
+ return name && allowed.includes(name) ? `https://${name}` : void 0;
39
+ }
40
+ function resolveAgainstOrigin(value, origin) {
41
+ if (!isSingleToken(value)) return;
42
+ if (!value.startsWith("/")) return value;
43
+ return origin ? `${origin}${value}` : void 0;
44
+ }
45
+ function buildSecurityTxt(options) {
46
+ const { contacts, now, origins, policy, preferredLanguages = [] } = options;
47
+ const validDays = normalizeSecurityTxtValidDays(options.validDays ?? 180);
48
+ const expires = /* @__PURE__ */ new Date(Math.floor((now.getTime() + validDays * DAY_MS) / DAY_MS) * DAY_MS);
49
+ const canonicals = [...new Set(origins.map((origin) => origin.replace(/\/+$/, "")).filter(Boolean))];
50
+ const languages = preferredLanguages.map((language) => language.trim()).filter(isSingleToken);
51
+ const lines = [...contacts.filter(isSingleToken).map((contact) => `Contact: ${contact}`), `Expires: ${expires.toISOString()}`];
52
+ const policyUri = resolveAgainstOrigin(policy, canonicals[0]);
53
+ if (policyUri) lines.push(`Policy: ${policyUri}`);
54
+ if (languages.length) lines.push(`Preferred-Languages: ${languages.join(", ")}`);
55
+ for (const origin of canonicals) lines.push(`Canonical: ${origin}${SECURITY_TXT_PATH}`);
56
+ return `${lines.join("\n")}\n`;
57
+ }
58
+ function resolveSecurityTxt(input) {
59
+ const config = input.config ?? {};
60
+ const contacts = normalizeSecurityTxtContacts(config.contact);
61
+ if (!contacts.length) return;
62
+ const siteOrigin = toSecurityTxtOrigin(input.siteUrl);
63
+ const requestOrigin = allowedRequestOrigin(input.requestHost, normalizeSecurityTxtList(config.hosts));
64
+ return buildSecurityTxt({
65
+ contacts,
66
+ now: input.now,
67
+ origins: [siteOrigin, requestOrigin].filter((origin) => !!origin),
68
+ policy: config.policy,
69
+ preferredLanguages: normalizeSecurityTxtList(config.preferredLanguages),
70
+ validDays: normalizeSecurityTxtValidDays(config.validDays)
71
+ });
72
+ }
73
+ const LT_RUNTIME_FEATURE_KEYS = {
74
+ ai: { basePath: "string" },
75
+ auth: {
76
+ basePath: "string",
77
+ loginPath: "string",
78
+ twoFactorRedirectPath: "string",
79
+ enablePasskey: "boolean",
80
+ enableTwoFactor: "boolean"
81
+ },
82
+ bug: {
83
+ autoOpenOnError: "boolean",
84
+ autoShow: "boolean",
85
+ buttonColor: "string",
86
+ buttonText: "string",
87
+ enabled: "boolean",
88
+ enableScreenshot: "boolean",
89
+ position: "string"
90
+ },
91
+ errorTranslation: {
92
+ defaultLocale: "string",
93
+ enabled: "boolean",
94
+ preload: "boolean"
95
+ },
96
+ sync: { basePath: "string" },
97
+ tus: {
98
+ defaultChunkSize: "number",
99
+ defaultEndpoint: "string",
100
+ resolveAgainstApi: "boolean"
101
+ }
102
+ };
103
+ const LT_RUNTIME_NESTED_KEYS = { auth: {
104
+ interceptor: {
105
+ enabled: "boolean",
106
+ publicPaths: "array"
107
+ },
108
+ systemSetup: {
109
+ enabled: "boolean",
110
+ setupPath: "string"
111
+ }
112
+ } };
113
+ function toLtEnvKey(camel) {
114
+ return camel.replace(/([a-z\d])([A-Z])/g, "$1_$2").toUpperCase();
115
+ }
116
+ function readLtRuntimeConfigFromEnv(env = processEnv$1(), options = {}) {
117
+ const value = (name) => {
118
+ const raw = env[name]?.trim();
119
+ return raw ? raw : void 0;
120
+ };
121
+ const lt = {};
122
+ for (const [feature, keys] of Object.entries(LT_RUNTIME_FEATURE_KEYS)) {
123
+ const options = {};
124
+ for (const [key, type] of Object.entries(keys)) {
125
+ const parsed = parseLtEnvValue(value(`NG_PUBLIC_LT_${toLtEnvKey(feature)}_${toLtEnvKey(key)}`), type);
126
+ if (parsed !== void 0) options[key] = parsed;
127
+ }
128
+ for (const [group, groupKeys] of Object.entries(LT_RUNTIME_NESTED_KEYS[feature] ?? {})) {
129
+ const nested = {};
130
+ for (const [key, type] of Object.entries(groupKeys)) {
131
+ const parsed = parseLtEnvValue(value(`NG_PUBLIC_LT_${toLtEnvKey(feature)}_${toLtEnvKey(group)}_${toLtEnvKey(key)}`), type);
132
+ if (parsed !== void 0) nested[key] = parsed;
133
+ }
134
+ if (Object.keys(nested).length) options[group] = nested;
135
+ }
136
+ if (Object.keys(options).length) lt[feature] = options;
137
+ }
138
+ const apiProxy = parseLtEnvValue(value("NG_PUBLIC_API_PROXY"), "boolean");
139
+ const commit = [value("NG_PUBLIC_APP_COMMIT"), value("APP_VERSION_COMMIT")].find((candidate) => candidate && candidate !== "unknown");
140
+ return {
141
+ public: {
142
+ apiProxy,
143
+ apiUrl: value("NG_PUBLIC_API_URL"),
144
+ appCommit: commit ?? "unknown",
145
+ appEnv: value("NG_PUBLIC_APP_ENV"),
146
+ appVersion: options.appVersion ?? value("NG_PUBLIC_APP_VERSION"),
147
+ cookiePrefix: value("NG_PUBLIC_COOKIE_PREFIX"),
148
+ lt,
149
+ siteUrl: value("NG_PUBLIC_SITE_URL"),
150
+ storagePrefix: value("NG_PUBLIC_STORAGE_PREFIX"),
151
+ ...options.extend?.(env)
152
+ },
153
+ serverApiUrl: value("NG_API_URL") ?? ""
154
+ };
155
+ }
156
+ function readLtRequestContext(env = processEnv$1(), options = {}) {
157
+ const config = readLtRuntimeConfigFromEnv(env, options);
158
+ return {
159
+ runtimeConfig: config.public,
160
+ serverApiUrl: config.serverApiUrl
161
+ };
162
+ }
163
+ function parseLtEnvValue(raw, type) {
164
+ if (raw === void 0) return;
165
+ switch (type) {
166
+ case "boolean": return /^(true|1|yes|on)$/i.test(raw) ? true : /^(false|0|no|off)$/i.test(raw) ? false : void 0;
167
+ case "number": {
168
+ const number = raw.trim() ? Number(raw) : NaN;
169
+ return Number.isFinite(number) ? number : void 0;
170
+ }
171
+ case "array": return raw.split(",").map((part) => part.trim()).filter(Boolean);
172
+ default: return raw;
173
+ }
174
+ }
175
+ function provideLtServerRuntimeConfig(env) {
176
+ return makeEnvironmentProviders([{
177
+ provide: LT_SERVER_RUNTIME_CONFIG,
178
+ useFactory: () => readLtRuntimeConfigFromEnv(typeof env === "function" ? env() : env ?? processEnv$1())
179
+ }]);
180
+ }
181
+ function processEnv$1() {
182
+ return globalThis.process?.env ?? {};
183
+ }
184
+ const SECURITY_HEADERS = Object.freeze({
185
+ "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=()",
186
+ "Referrer-Policy": "strict-origin",
187
+ "X-Content-Type-Options": "nosniff",
188
+ "X-DNS-Prefetch-Control": "off",
189
+ "X-Frame-Options": "DENY",
190
+ "X-Permitted-Cross-Domain-Policies": "none"
191
+ });
192
+ const LT_HSTS_VALUE = "max-age=31536000; includeSubDomains";
193
+ function isLtSecureRequest(req) {
194
+ const forwarded = headerValue(req.headers["x-forwarded-proto"])?.split(",")[0]?.trim().toLowerCase();
195
+ if (forwarded) return forwarded === "https";
196
+ return !!req.socket?.encrypted;
197
+ }
198
+ function buildLtSecurityHeaders(options) {
199
+ return options.secure ? {
200
+ ...SECURITY_HEADERS,
201
+ "Strict-Transport-Security": LT_HSTS_VALUE
202
+ } : { ...SECURITY_HEADERS };
203
+ }
204
+ function ltSecurityHeaders() {
205
+ return (req, res, next) => {
206
+ res.removeHeader("X-Powered-By");
207
+ for (const [name, value] of Object.entries(buildLtSecurityHeaders({ secure: isLtSecureRequest(req) }))) if (!res.hasHeader(name)) res.setHeader(name, value);
208
+ next();
209
+ };
210
+ }
211
+ function applyLtHtmlCacheHeaders(response) {
212
+ if (!(response.headers.get("content-type") ?? "").includes("text/html") || response.headers.has("cache-control")) return false;
213
+ response.headers.set("cache-control", "private, no-cache");
214
+ const vary = response.headers.get("vary");
215
+ response.headers.set("vary", vary ? `${vary}, Cookie` : "Cookie");
216
+ return true;
217
+ }
218
+ function ltSecurityTxt(options = {}) {
219
+ return (req, res, next) => {
220
+ if ((req.url ?? "").split("?")[0] !== "/.well-known/security.txt" || req.method !== "GET" && req.method !== "HEAD") {
221
+ next();
222
+ return;
223
+ }
224
+ const env = options.env ?? processEnv();
225
+ const fromEnv = (name) => env[name] === void 0 || env[name] === "" ? void 0 : env[name];
226
+ const body = resolveSecurityTxt({
227
+ config: {
228
+ contact: fromEnv("NG_LT_SECURITY_TXT_CONTACT")?.split(",") ?? options.contact ?? "mailto:security@lenne.tech",
229
+ hosts: fromEnv("NG_LT_SECURITY_TXT_HOSTS") ?? options.hosts ?? [],
230
+ policy: fromEnv("NG_LT_SECURITY_TXT_POLICY") ?? options.policy,
231
+ preferredLanguages: fromEnv("NG_LT_SECURITY_TXT_PREFERRED_LANGUAGES") ?? options.preferredLanguages ?? SECURITY_TXT_DEFAULT_LANGUAGES,
232
+ validDays: fromEnv("NG_LT_SECURITY_TXT_VALID_DAYS") ?? options.validDays ?? 180
233
+ },
234
+ now: /* @__PURE__ */ new Date(),
235
+ requestHost: headerValue(req.headers["x-forwarded-host"])?.split(",")[0]?.trim() || headerValue(req.headers.host),
236
+ siteUrl: options.siteUrl ?? readLtRuntimeConfigFromEnv(env).public.siteUrl
237
+ });
238
+ if (!body) {
239
+ res.statusCode = 404;
240
+ res.setHeader("content-type", "text/plain; charset=utf-8");
241
+ res.end("Not Found");
242
+ return;
243
+ }
244
+ res.statusCode = 200;
245
+ res.setHeader("content-type", "text/plain; charset=utf-8");
246
+ res.setHeader("cache-control", "no-store");
247
+ res.end(req.method === "HEAD" ? void 0 : body);
248
+ };
249
+ }
250
+ function resolveLtBuildCommit(env = processEnv()) {
251
+ for (const candidate of [env["NG_PUBLIC_APP_COMMIT"], env["APP_VERSION_COMMIT"]]) if (typeof candidate === "string" && candidate.trim() && candidate !== "unknown") return candidate;
252
+ return "unknown";
253
+ }
254
+ function ltBuildIdentity(options = {}) {
255
+ const path = options.path ?? "/api/build-identity";
256
+ return (req, res, next) => {
257
+ if ((req.url ?? "").split("?")[0] !== path || req.method !== "GET") {
258
+ next();
259
+ return;
260
+ }
261
+ const env = options.env ?? processEnv();
262
+ res.statusCode = 200;
263
+ res.setHeader("content-type", "application/json; charset=utf-8");
264
+ res.setHeader("cache-control", "no-store");
265
+ res.end(JSON.stringify({
266
+ commit: resolveLtBuildCommit(env),
267
+ version: options.version ?? env["NG_PUBLIC_APP_VERSION"] ?? "0.0.0"
268
+ }));
269
+ };
270
+ }
271
+ function headerValue(value) {
272
+ return Array.isArray(value) ? value[0] : value;
273
+ }
274
+ function processEnv() {
275
+ return globalThis.process?.env ?? {};
276
+ }
277
+ async function withLtRuntimeConfigScript(response, config, options = {}) {
278
+ if (!(response.headers.get("content-type") ?? "").includes("text/html")) return response;
279
+ const html = injectLtRuntimeConfigScript(await response.text(), config, options);
280
+ const headers = new Headers(response.headers);
281
+ headers.delete("content-length");
282
+ return new Response(html, {
283
+ headers,
284
+ status: response.status,
285
+ statusText: response.statusText
286
+ });
287
+ }
288
+ function ltAngularRequestHandler(engine, options = {}) {
289
+ return (req, res, next) => {
290
+ const context = readLtRequestContext(options.env, options);
291
+ engine.handle(req, context).then(async (response) => {
292
+ if (!response) {
293
+ next();
294
+ return;
295
+ }
296
+ if (options.htmlNoCache !== false) applyLtHtmlCacheHeaders(response);
297
+ await writeResponseToNodeResponse(await withLtRuntimeConfigScript(response, context.runtimeConfig, { submitGuard: options.submitGuard }), res);
298
+ }).catch(next);
299
+ };
300
+ }
301
+ const FORWARDED_REQUEST_HEADERS = [
302
+ "accept",
303
+ "accept-language",
304
+ "authorization",
305
+ "content-type",
306
+ "cookie",
307
+ "origin",
308
+ "referer",
309
+ "user-agent",
310
+ "x-file-id",
311
+ "x-system-setup-token",
312
+ "x-tenant-id",
313
+ "tus-resumable",
314
+ "upload-length",
315
+ "upload-metadata",
316
+ "upload-offset",
317
+ "upload-concat",
318
+ "upload-defer-length"
319
+ ];
320
+ const HOP_BY_HOP = /* @__PURE__ */ new Set([
321
+ "connection",
322
+ "content-encoding",
323
+ "content-length",
324
+ "keep-alive",
325
+ "proxy-authenticate",
326
+ "proxy-authorization",
327
+ "te",
328
+ "trailer",
329
+ "transfer-encoding",
330
+ "upgrade"
331
+ ]);
332
+ function rewriteLtProxyCookie(cookie, secure) {
333
+ const [pair = "", ...attributes] = cookie.split(";").map((part) => part.trim());
334
+ return [
335
+ pair,
336
+ "Path=/",
337
+ ...attributes.filter((part) => part && !/^domain=/i.test(part) && !/^path=/i.test(part) && (secure || !/^secure$/i.test(part)))
338
+ ].join("; ");
339
+ }
340
+ function rewriteLtProxyLocation(location, target, prefix) {
341
+ if (location.startsWith("/") && !location.startsWith("//")) return `${prefix}${location}`;
342
+ try {
343
+ const url = new URL(location);
344
+ const base = new URL(target);
345
+ if (url.origin !== base.origin) return location;
346
+ const basePath = base.pathname.replace(/\/+$/, "");
347
+ return `${prefix}${basePath && url.pathname.startsWith(`${basePath}/`) ? url.pathname.slice(basePath.length) : url.pathname}${url.search}${url.hash}`;
348
+ } catch {
349
+ return location;
350
+ }
351
+ }
352
+ function ltApiProxy(options = {}) {
353
+ const prefix = (options.prefix ?? "/api").replace(/\/+$/, "");
354
+ return (req, res, next) => {
355
+ const url = req.url ?? "";
356
+ if (url !== prefix && !url.startsWith(`${prefix}/`) && !url.startsWith(`${prefix}?`)) {
357
+ next();
358
+ return;
359
+ }
360
+ const runtime = readLtRuntimeConfigFromEnv(options.env ?? globalThis.process?.env ?? {});
361
+ const enabled = options.enabled ?? runtime.public.apiProxy === true;
362
+ const target = (options.target ?? (runtime.serverApiUrl || runtime.public.apiUrl || "")).replace(/\/+$/, "");
363
+ if (!enabled || !target) {
364
+ next();
365
+ return;
366
+ }
367
+ const headers = new Headers();
368
+ for (const name of FORWARDED_REQUEST_HEADERS) {
369
+ const value = req.headers[name];
370
+ if (value !== void 0) headers.set(name, Array.isArray(value) ? value.join(", ") : value);
371
+ }
372
+ const method = (req.method ?? "GET").toUpperCase();
373
+ const hasBody = method !== "GET" && method !== "HEAD";
374
+ const controller = new AbortController();
375
+ res.on("close", () => controller.abort());
376
+ fetch(`${target}${url.slice(prefix.length) || "/"}`, {
377
+ body: hasBody ? Readable.toWeb(req) : void 0,
378
+ headers,
379
+ method,
380
+ redirect: "manual",
381
+ signal: controller.signal,
382
+ ...hasBody ? { duplex: "half" } : {}
383
+ }).then(async (response) => {
384
+ res.statusCode = response.status;
385
+ const secure = isLtSecureRequest(req);
386
+ response.headers.forEach((value, name) => {
387
+ if (name === "location" || name === "content-location") res.setHeader(name, rewriteLtProxyLocation(value, target, prefix));
388
+ else if (!HOP_BY_HOP.has(name) && name !== "set-cookie") res.setHeader(name, value);
389
+ });
390
+ const cookies = response.headers.getSetCookie?.() ?? [];
391
+ if (cookies.length) res.setHeader("set-cookie", cookies.map((cookie) => rewriteLtProxyCookie(cookie, secure)));
392
+ if (!response.body) {
393
+ res.end();
394
+ return;
395
+ }
396
+ pipeline(Readable.fromWeb(response.body), res, () => void 0);
397
+ }).catch((error) => {
398
+ if (controller.signal.aborted) return;
399
+ console.error("[@lenne.tech/ng-base/server] API proxy error:", error);
400
+ res.statusCode = 502;
401
+ res.setHeader("content-type", "application/json");
402
+ res.end(JSON.stringify({ message: "API proxy error" }));
403
+ });
404
+ };
405
+ }
406
+ export { LT_HSTS_VALUE, LT_RUNTIME_FEATURE_KEYS, SECURITY_TXT_DEFAULT_CONTACT, SECURITY_TXT_DEFAULT_LANGUAGES, SECURITY_TXT_DEFAULT_VALID_DAYS, SECURITY_TXT_PATH, allowedRequestOrigin, applyLtHtmlCacheHeaders, buildLtSecurityHeaders, buildSecurityTxt as buildLtSecurityTxt, isLtSecureRequest, ltAngularRequestHandler, ltApiProxy, ltBuildIdentity, ltSecurityHeaders, ltSecurityTxt, normalizeSecurityTxtContacts, normalizeSecurityTxtList, normalizeSecurityTxtValidDays, parseLtEnvValue, provideLtServerRuntimeConfig, readLtRequestContext, readLtRuntimeConfigFromEnv, resolveLtBuildCommit, resolveSecurityTxt as resolveLtSecurityTxt, rewriteLtProxyCookie, rewriteLtProxyLocation, toLtEnvKey, toSecurityTxtOrigin, withLtRuntimeConfigScript };
407
+
408
+ //# sourceMappingURL=lenne.tech-ng-base-server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lenne.tech-ng-base-server.mjs","names":["processEnv"],"sources":["../../../projects/ng-base/server/src/lib/security-txt.ts","../../../projects/ng-base/server/src/lib/runtime-env.ts","../../../projects/ng-base/server/src/lib/middlewares.ts","../../../projects/ng-base/server/src/lib/angular-handler.ts","../../../projects/ng-base/server/src/lib/api-proxy.ts"],"sourcesContent":["/**\n * security.txt according to RFC 9116, built per request.\n *\n * Ported from the lenne.Tech website (DEV-3602), where it has been live since 2026-10-13.\n * Pure functions only, so the route stays a thin adapter and everything that decides the\n * file's content is unit-testable without a Nitro context.\n */\n\nexport const SECURITY_TXT_PATH = '/.well-known/security.txt';\nexport const SECURITY_TXT_DEFAULT_CONTACT = 'mailto:security@lenne.tech';\nexport const SECURITY_TXT_DEFAULT_LANGUAGES = ['de', 'en'];\nexport const SECURITY_TXT_DEFAULT_VALID_DAYS = 180;\n/** RFC 9116 recommends an `Expires` less than a year away. */\nconst SECURITY_TXT_MAX_VALID_DAYS = 365;\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/** RFC 9116 §2.5.3: a contact is a URI, and a web URI must be https. */\nconst CONTACT_URI = /^(?:mailto:|tel:|https:\\/\\/)\\S/i;\n\nexport interface SecurityTxtOptions {\n /** Contact URIs (`mailto:`, `https:` or `tel:`), in order of preference. */\n contacts: string[];\n /** Point in time the file is built for; `Expires` is derived from it. */\n now: Date;\n /** Origins the file is served from; each becomes one `Canonical` line. */\n origins: string[];\n /** URI of the vulnerability disclosure policy, or a path resolved against the first origin. */\n policy?: string;\n /** Language tags in order of preference. */\n preferredLanguages?: string[];\n /** Days between `now` and `Expires`. */\n validDays?: number;\n}\n\n/**\n * Keeps a configured value only if it is a single token. Every value ends up on a line of its\n * own, so a line break or blank inside one would forge an additional field.\n */\nfunction isSingleToken(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0 && !/\\s/.test(value);\n}\n\n/**\n * Normalises the configured contact(s). Accepts a string or an array (`ltSecurityTxt()` splits the comma-separated\n * runtime override `NG_LT_SECURITY_TXT_CONTACT`).\n *\n * Whatever is not a usable URI is dropped. `security@example.com` is the obvious typo, and scanners\n * treat the file it would produce as invalid; with no contact left, the route answers 404 instead.\n */\nexport function normalizeSecurityTxtContacts(contact: unknown): string[] {\n const values = Array.isArray(contact) ? contact : [contact];\n return values\n .map((value) => (typeof value === 'string' ? value.trim() : value))\n .filter(isSingleToken)\n .filter((value) => CONTACT_URI.test(value));\n}\n\n/**\n * Normalises a list option (languages, hosts). A runtime override via an environment variable\n * arrives as a string, so `\"de, en\"` is accepted as well as `['de', 'en']`.\n */\nexport function normalizeSecurityTxtList(value: unknown): string[] {\n const values = typeof value === 'string' ? value.split(',') : Array.isArray(value) ? value : [];\n return values.map((entry) => (typeof entry === 'string' ? entry.trim() : entry)).filter(isSingleToken);\n}\n\n/**\n * Clamps `validDays` into the window RFC 9116 recommends. A non-finite or non-positive value\n * falls back to the default instead of producing an `Expires` in the past.\n */\nexport function normalizeSecurityTxtValidDays(validDays: unknown): number {\n const days = Number(validDays);\n if (!Number.isFinite(days) || days < 1) {\n return SECURITY_TXT_DEFAULT_VALID_DAYS;\n }\n return Math.min(Math.floor(days), SECURITY_TXT_MAX_VALID_DAYS);\n}\n\n/**\n * Turns a configured site URL into an origin (`https://example.com`), dropping path, query and\n * trailing slash. Anything that is not an absolute http(s) URL yields `undefined`.\n */\nexport function toSecurityTxtOrigin(url: string | undefined): string | undefined {\n if (!url) {\n return undefined;\n }\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'https:' || parsed.protocol === 'http:' ? parsed.origin : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Turns the requested host into an origin, but only if it is one the site is known to be served\n * from. The host comes from a request header, so anything else must not end up in the file.\n */\nexport function allowedRequestOrigin(host: string | undefined, allowedHosts: string[]): string | undefined {\n const name = host?.trim().toLowerCase();\n const allowed = allowedHosts.map((entry) => entry.trim().toLowerCase());\n return name && allowed.includes(name) ? `https://${name}` : undefined;\n}\n\n/** Resolves a path against the first origin; absolute URIs pass through unchanged. */\nfunction resolveAgainstOrigin(value: string | undefined, origin: string | undefined): string | undefined {\n if (!isSingleToken(value)) {\n return undefined;\n }\n if (!value.startsWith('/')) {\n return value;\n }\n return origin ? `${origin}${value}` : undefined;\n}\n\n/**\n * Builds a security.txt according to RFC 9116.\n *\n * `Expires` is relative to `now`, so a file built per request never goes stale, no matter how\n * long ago the last deployment was. It is cut to midnight UTC, which makes the file valid for up\n * to a day less than `validDays` and keeps it byte-identical for a whole day.\n */\nexport function buildSecurityTxt(options: SecurityTxtOptions): string {\n const { contacts, now, origins, policy, preferredLanguages = [] } = options;\n const validDays = normalizeSecurityTxtValidDays(options.validDays ?? SECURITY_TXT_DEFAULT_VALID_DAYS);\n const expires = new Date(Math.floor((now.getTime() + validDays * DAY_MS) / DAY_MS) * DAY_MS);\n const canonicals = [...new Set(origins.map((origin) => origin.replace(/\\/+$/, '')).filter(Boolean))];\n const languages = preferredLanguages.map((language) => language.trim()).filter(isSingleToken);\n\n const lines = [...contacts.filter(isSingleToken).map((contact) => `Contact: ${contact}`), `Expires: ${expires.toISOString()}`];\n const policyUri = resolveAgainstOrigin(policy, canonicals[0]);\n if (policyUri) {\n lines.push(`Policy: ${policyUri}`);\n }\n if (languages.length) {\n lines.push(`Preferred-Languages: ${languages.join(', ')}`);\n }\n for (const origin of canonicals) {\n lines.push(`Canonical: ${origin}${SECURITY_TXT_PATH}`);\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/** The server-only runtime config the module writes to `runtimeConfig.ltExtensions.securityTxt`. */\nexport interface SecurityTxtRuntimeConfig {\n contact?: string | string[];\n hosts?: string | string[];\n policy?: string;\n preferredLanguages?: string | string[];\n validDays?: number | string;\n}\n\n/**\n * Turns the runtime config and the request into the file's content, or `undefined` when no\n * usable contact is left (the route then answers 404).\n *\n * `Canonical` names the configured site URL and, in addition, the requested host if it is one of\n * the configured `hosts`. A site served under several hostnames without a redirect needs the\n * second line: RFC 9116 expects the URI a file was fetched from among its Canonical lines.\n */\nexport function resolveSecurityTxt(input: {\n config: SecurityTxtRuntimeConfig | undefined;\n now: Date;\n requestHost: string | undefined;\n siteUrl: string | undefined;\n}): string | undefined {\n const config = input.config ?? {};\n const contacts = normalizeSecurityTxtContacts(config.contact);\n if (!contacts.length) {\n return undefined;\n }\n\n const siteOrigin = toSecurityTxtOrigin(input.siteUrl);\n const requestOrigin = allowedRequestOrigin(input.requestHost, normalizeSecurityTxtList(config.hosts));\n\n return buildSecurityTxt({\n contacts,\n now: input.now,\n origins: [siteOrigin, requestOrigin].filter((origin): origin is string => !!origin),\n policy: config.policy,\n preferredLanguages: normalizeSecurityTxtList(config.preferredLanguages),\n validDays: normalizeSecurityTxtValidDays(config.validDays),\n });\n}\n","import { makeEnvironmentProviders, type EnvironmentProviders } from '@angular/core';\nimport { LT_SERVER_RUNTIME_CONFIG, type LtPublicFeatureConfig, type LtRequestContext, type LtRuntimeConfig, type LtServerRuntimeConfig } from '@lenne.tech/ng-base';\n\n/** Environment map (`process.env` shape). */\nexport type LtEnv = Record<string, string | undefined>;\n\n/**\n * Feature options that may be overridden at runtime via `NG_PUBLIC_LT_<FEATURE>_<OPTION>` (camelCase ↔ SCREAMING_SNAKE).\n * Only listed keys are read, so an env name maps to exactly one option. Values are parsed by the type of the default:\n * booleans (`true`/`false`), numbers, string arrays (comma-separated), strings.\n */\nexport const LT_RUNTIME_FEATURE_KEYS: Readonly<Record<string, Readonly<Record<string, 'array' | 'boolean' | 'number' | 'string'>>>> = {\n ai: { basePath: 'string' },\n auth: { basePath: 'string', loginPath: 'string', twoFactorRedirectPath: 'string', enablePasskey: 'boolean', enableTwoFactor: 'boolean' },\n bug: {\n autoOpenOnError: 'boolean',\n autoShow: 'boolean',\n buttonColor: 'string',\n buttonText: 'string',\n enabled: 'boolean',\n enableScreenshot: 'boolean',\n position: 'string',\n },\n errorTranslation: { defaultLocale: 'string', enabled: 'boolean', preload: 'boolean' },\n sync: { basePath: 'string' },\n tus: { defaultChunkSize: 'number', defaultEndpoint: 'string', resolveAgainstApi: 'boolean' },\n};\n\n/** Nested auth keys (`NG_PUBLIC_LT_AUTH_SYSTEM_SETUP_ENABLED`, `…_INTERCEPTOR_PUBLIC_PATHS`, …). */\nconst LT_RUNTIME_NESTED_KEYS: Readonly<Record<string, Readonly<Record<string, Readonly<Record<string, 'array' | 'boolean' | 'number' | 'string'>>>>>> = {\n auth: {\n interceptor: { enabled: 'boolean', publicPaths: 'array' },\n systemSetup: { enabled: 'boolean', setupPath: 'string' },\n },\n};\n\n/** `loginPath` → `LOGIN_PATH`. */\nexport function toLtEnvKey(camel: string): string {\n return camel.replace(/([a-z\\d])([A-Z])/g, '$1_$2').toUpperCase();\n}\n\n/**\n * Read the runtime configuration from the server environment (default `process.env`), the counterpart of Nuxt's\n * `NUXT_*` → `runtimeConfig` mapping:\n *\n * | Variable | Target |\n * |---|---|\n * | `NG_PUBLIC_API_URL` | `apiUrl` |\n * | `NG_API_URL` | `serverApiUrl` (SSR only, never transferred) |\n * | `NG_PUBLIC_SITE_URL` | `siteUrl` |\n * | `NG_PUBLIC_STORAGE_PREFIX` | `storagePrefix` |\n * | `NG_PUBLIC_COOKIE_PREFIX` | `cookiePrefix` |\n * | `NG_PUBLIC_API_PROXY` | `apiProxy` (`true`/`false`; unset = `null`) |\n * | `NG_PUBLIC_APP_ENV` | `appEnv` |\n * | `NG_PUBLIC_APP_COMMIT`, fallback `APP_VERSION_COMMIT` | `appCommit` |\n * | `NG_PUBLIC_APP_VERSION` | `appVersion` (or `options.appVersion`) |\n * | `NG_PUBLIC_LT_<FEATURE>_<OPTION>` | `lt.<feature>.<option>` (see {@link LT_RUNTIME_FEATURE_KEYS}) |\n *\n * Unset variables stay `undefined`, so code defaults keep applying.\n */\nexport function readLtRuntimeConfigFromEnv(env: LtEnv = processEnv(), options: LtRuntimeEnvOptions = {}): LtServerRuntimeConfig {\n const value = (name: string) => {\n const raw = env[name]?.trim();\n return raw ? raw : undefined;\n };\n const lt: LtPublicFeatureConfig = {};\n for (const [feature, keys] of Object.entries(LT_RUNTIME_FEATURE_KEYS)) {\n const options: Record<string, unknown> = {};\n for (const [key, type] of Object.entries(keys)) {\n const parsed = parseLtEnvValue(value(`NG_PUBLIC_LT_${toLtEnvKey(feature)}_${toLtEnvKey(key)}`), type);\n if (parsed !== undefined) {\n options[key] = parsed;\n }\n }\n for (const [group, groupKeys] of Object.entries(LT_RUNTIME_NESTED_KEYS[feature] ?? {})) {\n const nested: Record<string, unknown> = {};\n for (const [key, type] of Object.entries(groupKeys)) {\n const parsed = parseLtEnvValue(value(`NG_PUBLIC_LT_${toLtEnvKey(feature)}_${toLtEnvKey(group)}_${toLtEnvKey(key)}`), type);\n if (parsed !== undefined) {\n nested[key] = parsed;\n }\n }\n if (Object.keys(nested).length) {\n options[group] = nested;\n }\n }\n if (Object.keys(options).length) {\n lt[feature] = options;\n }\n }\n const apiProxy = parseLtEnvValue(value('NG_PUBLIC_API_PROXY'), 'boolean') as boolean | undefined;\n const commit = [value('NG_PUBLIC_APP_COMMIT'), value('APP_VERSION_COMMIT')].find((candidate) => candidate && candidate !== 'unknown');\n const publicConfig: Partial<LtRuntimeConfig> = {\n apiProxy,\n apiUrl: value('NG_PUBLIC_API_URL'),\n appCommit: commit ?? 'unknown',\n appEnv: value('NG_PUBLIC_APP_ENV'),\n appVersion: options.appVersion ?? value('NG_PUBLIC_APP_VERSION'),\n cookiePrefix: value('NG_PUBLIC_COOKIE_PREFIX'),\n lt,\n siteUrl: value('NG_PUBLIC_SITE_URL'),\n storagePrefix: value('NG_PUBLIC_STORAGE_PREFIX'),\n };\n return { public: { ...publicConfig, ...options.extend?.(env) }, serverApiUrl: value('NG_API_URL') ?? '' };\n}\n\n/** Options of {@link readLtRuntimeConfigFromEnv} / {@link readLtRequestContext}. */\nexport interface LtRuntimeEnvOptions {\n /** Version of the running build (e.g. from package.json); overrides `NG_PUBLIC_APP_VERSION`. */\n appVersion?: string;\n /** Additional public values of the project (e.g. `{ plausibleApiHost: env.NG_PUBLIC_PLAUSIBLE_API_HOST }`). */\n extend?: (env: LtEnv) => Record<string, unknown>;\n}\n\n/**\n * Build the request context for `AngularNodeAppEngine.handle(req, context)` from the environment, per request (a\n * changed env needs no rebuild). Angular code reads it through `REQUEST_CONTEXT` (`LT_SERVER_RUNTIME_CONFIG`), and the\n * public part must be written into the HTML with `injectLtRuntimeConfigScript()` / `ltAngularRequestHandler()`.\n */\nexport function readLtRequestContext(env: LtEnv = processEnv(), options: LtRuntimeEnvOptions = {}): LtRequestContext {\n const config = readLtRuntimeConfigFromEnv(env, options);\n return { runtimeConfig: config.public, serverApiUrl: config.serverApiUrl };\n}\n\n/** Parse one env value by its option type (`undefined` for unset or unparsable values). */\nexport function parseLtEnvValue(raw: string | undefined, type: 'array' | 'boolean' | 'number' | 'string'): unknown {\n if (raw === undefined) {\n return undefined;\n }\n switch (type) {\n case 'boolean':\n return /^(true|1|yes|on)$/i.test(raw) ? true : /^(false|0|no|off)$/i.test(raw) ? false : undefined;\n case 'number': {\n // `Number('')` is 0: a blank value is unparsable, not zero.\n const number = raw.trim() ? Number(raw) : Number.NaN;\n return Number.isFinite(number) ? number : undefined;\n }\n case 'array':\n return raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean);\n default:\n return raw;\n }\n}\n\n/**\n * Alternative to the request context for servers that call `handle(req)` without one: reads the `NG_*` environment\n * at request time in the app (every SSR render bootstraps it) and provides `LT_SERVER_RUNTIME_CONFIG`. The browser\n * still needs `<script id=\"ng-runtime-config\">` in the HTML, so prefer `ltAngularRequestHandler()`, which does both.\n */\nexport function provideLtServerRuntimeConfig(env?: LtEnv | (() => LtEnv)): EnvironmentProviders {\n return makeEnvironmentProviders([\n {\n provide: LT_SERVER_RUNTIME_CONFIG,\n useFactory: () => readLtRuntimeConfigFromEnv(typeof env === 'function' ? env() : (env ?? processEnv())),\n },\n ]);\n}\n\nfunction processEnv(): LtEnv {\n return (globalThis as { process?: { env?: LtEnv } }).process?.env ?? {};\n}\n","/// <reference types=\"node\" />\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nimport { resolveSecurityTxt, SECURITY_TXT_DEFAULT_CONTACT, SECURITY_TXT_DEFAULT_LANGUAGES, SECURITY_TXT_DEFAULT_VALID_DAYS, SECURITY_TXT_PATH } from './security-txt';\nimport { readLtRuntimeConfigFromEnv, type LtEnv } from './runtime-env';\n\n/** Express-compatible middleware (`(req, res, next)`), also usable with plain `node:http`. */\nexport type LtNodeMiddleware = (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void;\n\nconst SECURITY_HEADERS: Readonly<Record<string, string>> = Object.freeze({\n 'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), payment=()',\n 'Referrer-Policy': 'strict-origin',\n 'X-Content-Type-Options': 'nosniff',\n 'X-DNS-Prefetch-Control': 'off',\n 'X-Frame-Options': 'DENY',\n 'X-Permitted-Cross-Domain-Policies': 'none',\n});\n\n/** HSTS header value set on HTTPS requests. */\nexport const LT_HSTS_VALUE = 'max-age=31536000; includeSubDomains';\n\n/** Whether the request came in over HTTPS (`X-Forwarded-Proto` first, then the socket). */\nexport function isLtSecureRequest(req: Pick<IncomingMessage, 'headers'> & { socket?: unknown }): boolean {\n const forwarded = headerValue(req.headers['x-forwarded-proto'])?.split(',')[0]?.trim().toLowerCase();\n if (forwarded) {\n return forwarded === 'https';\n }\n return !!(req.socket as { encrypted?: boolean } | undefined)?.encrypted;\n}\n\n/** The security headers for a request (same set as nuxt-base-starter; no CSP by design). */\nexport function buildLtSecurityHeaders(options: { secure: boolean }): Record<string, string> {\n return options.secure ? { ...SECURITY_HEADERS, 'Strict-Transport-Security': LT_HSTS_VALUE } : { ...SECURITY_HEADERS };\n}\n\n/**\n * Security headers on every response: `nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: strict-origin`,\n * `Permissions-Policy`, `X-DNS-Prefetch-Control: off`, `X-Permitted-Cross-Domain-Policies: none`, HSTS on HTTPS;\n * removes `X-Powered-By`; never overwrites a header a route already set.\n */\nexport function ltSecurityHeaders(): LtNodeMiddleware {\n return (req, res, next) => {\n res.removeHeader('X-Powered-By');\n for (const [name, value] of Object.entries(buildLtSecurityHeaders({ secure: isLtSecureRequest(req) }))) {\n if (!res.hasHeader(name)) {\n res.setHeader(name, value);\n }\n }\n next();\n };\n}\n\n/**\n * Cache headers for SSR HTML: `Cache-Control: private, no-cache` and `Vary: Cookie` (the page depends on the auth\n * cookie), unless the response already has a `Cache-Control`. Apply it to the `Response` of `AngularNodeAppEngine.handle()`\n * before `writeResponseToNodeResponse()`. Returns whether the headers were set.\n */\nexport function applyLtHtmlCacheHeaders(response: Response): boolean {\n if (!(response.headers.get('content-type') ?? '').includes('text/html') || response.headers.has('cache-control')) {\n return false;\n }\n response.headers.set('cache-control', 'private, no-cache');\n const vary = response.headers.get('vary');\n response.headers.set('vary', vary ? `${vary}, Cookie` : 'Cookie');\n return true;\n}\n\n/** Options of {@link ltSecurityTxt}. Values can be overridden per stage via `NG_LT_SECURITY_TXT_*`. */\nexport interface LtSecurityTxtHandlerOptions {\n /** Contact URI(s) (`mailto:`, `https://`, `tel:`), default `mailto:security@lenne.tech`. Env `NG_LT_SECURITY_TXT_CONTACT` (comma-separated). */\n contact?: string | string[];\n /** Hostnames served without redirect; a request for one adds a second `Canonical` line. Env `NG_LT_SECURITY_TXT_HOSTS`. */\n hosts?: string[];\n /** Policy URI or path (resolved against the site URL). Env `NG_LT_SECURITY_TXT_POLICY`. */\n policy?: string;\n /** Language tags (default `de, en`). Env `NG_LT_SECURITY_TXT_PREFERRED_LANGUAGES`. */\n preferredLanguages?: string[];\n /** Site URL for `Canonical` (default `NG_PUBLIC_SITE_URL`). */\n siteUrl?: string;\n /** Days until `Expires` (default 180, max 365). Env `NG_LT_SECURITY_TXT_VALID_DAYS`. */\n validDays?: number;\n /** Environment to read the overrides from (default `process.env`). */\n env?: LtEnv;\n}\n\n/**\n * Serve `/.well-known/security.txt` (RFC 9116), built per request: GET/HEAD, `text/plain`, `no-store`; 404 when no\n * valid contact is configured. Register it only where somebody reads the contact address.\n *\n * @example server.ts: app.use(ltSecurityTxt({ contact: 'mailto:security@customer.example' }))\n */\nexport function ltSecurityTxt(options: LtSecurityTxtHandlerOptions = {}): LtNodeMiddleware {\n return (req, res, next) => {\n const path = (req.url ?? '').split('?')[0];\n if (path !== SECURITY_TXT_PATH || (req.method !== 'GET' && req.method !== 'HEAD')) {\n next();\n return;\n }\n const env = options.env ?? processEnv();\n const fromEnv = (name: string) => (env[name] === undefined || env[name] === '' ? undefined : env[name]);\n const body = resolveSecurityTxt({\n config: {\n contact: fromEnv('NG_LT_SECURITY_TXT_CONTACT')?.split(',') ?? options.contact ?? SECURITY_TXT_DEFAULT_CONTACT,\n hosts: fromEnv('NG_LT_SECURITY_TXT_HOSTS') ?? options.hosts ?? [],\n policy: fromEnv('NG_LT_SECURITY_TXT_POLICY') ?? options.policy,\n preferredLanguages: fromEnv('NG_LT_SECURITY_TXT_PREFERRED_LANGUAGES') ?? options.preferredLanguages ?? SECURITY_TXT_DEFAULT_LANGUAGES,\n validDays: fromEnv('NG_LT_SECURITY_TXT_VALID_DAYS') ?? options.validDays ?? SECURITY_TXT_DEFAULT_VALID_DAYS,\n },\n now: new Date(),\n requestHost: headerValue(req.headers['x-forwarded-host'])?.split(',')[0]?.trim() || headerValue(req.headers.host),\n siteUrl: options.siteUrl ?? readLtRuntimeConfigFromEnv(env).public.siteUrl,\n });\n if (!body) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.end('Not Found');\n return;\n }\n res.statusCode = 200;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.setHeader('cache-control', 'no-store');\n res.end(req.method === 'HEAD' ? undefined : body);\n };\n}\n\n/** Options of {@link ltBuildIdentity}. */\nexport interface LtBuildIdentityOptions {\n /** Route (default `/api/build-identity`). */\n path?: string;\n /** App version (default `NG_PUBLIC_APP_VERSION`, else `0.0.0`). */\n version?: string;\n /** Environment (default `process.env`). */\n env?: LtEnv;\n}\n\n/** Commit of the running build: `NG_PUBLIC_APP_COMMIT`, else `APP_VERSION_COMMIT` (TurboOps), else `unknown`. */\nexport function resolveLtBuildCommit(env: LtEnv = processEnv()): string {\n for (const candidate of [env['NG_PUBLIC_APP_COMMIT'], env['APP_VERSION_COMMIT']]) {\n if (typeof candidate === 'string' && candidate.trim() && candidate !== 'unknown') {\n return candidate;\n }\n }\n return 'unknown';\n}\n\n/** `GET /api/build-identity` → `{ commit, version }` (no-store), used by the admin system page to detect drift. */\nexport function ltBuildIdentity(options: LtBuildIdentityOptions = {}): LtNodeMiddleware {\n const path = options.path ?? '/api/build-identity';\n return (req, res, next) => {\n if ((req.url ?? '').split('?')[0] !== path || req.method !== 'GET') {\n next();\n return;\n }\n const env = options.env ?? processEnv();\n res.statusCode = 200;\n res.setHeader('content-type', 'application/json; charset=utf-8');\n res.setHeader('cache-control', 'no-store');\n res.end(JSON.stringify({ commit: resolveLtBuildCommit(env), version: options.version ?? env['NG_PUBLIC_APP_VERSION'] ?? '0.0.0' }));\n };\n}\n\nfunction headerValue(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction processEnv(): LtEnv {\n return (globalThis as { process?: { env?: LtEnv } }).process?.env ?? {};\n}\n","/// <reference types=\"node\" />\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nimport { writeResponseToNodeResponse } from '@angular/ssr/node';\nimport { injectLtRuntimeConfigScript, type LtRequestContext, type LtRuntimeConfig } from '@lenne.tech/ng-base';\n\nimport type { LtNodeMiddleware } from './middlewares';\nimport { applyLtHtmlCacheHeaders } from './middlewares';\nimport { readLtRequestContext, type LtEnv, type LtRuntimeEnvOptions } from './runtime-env';\n\n/** The part of `AngularNodeAppEngine` the handler needs. */\nexport interface LtAngularEngine {\n handle(request: IncomingMessage, requestContext?: unknown): Promise<Response | null>;\n}\n\n/** Options of {@link ltAngularRequestHandler}. */\nexport interface LtAngularRequestHandlerOptions extends LtRuntimeEnvOptions {\n /** Set `Cache-Control: private, no-cache` + `Vary: Cookie` on HTML without own cache header (default `true`). */\n htmlNoCache?: boolean;\n /** Write the pre-hydration submit guard into the HTML (default `true`, see `LT_PRE_HYDRATION_SUBMIT_GUARD_SCRIPT`). */\n submitGuard?: boolean;\n /** Environment (default `process.env`, read per request). */\n env?: LtEnv;\n}\n\n/**\n * Write the public runtime configuration as `<script id=\"ng-runtime-config\">` into an HTML response (SSR and\n * client-rendered routes alike). Non-HTML responses are returned unchanged.\n */\nexport async function withLtRuntimeConfigScript(response: Response, config: Partial<LtRuntimeConfig>, options: { submitGuard?: boolean } = {}): Promise<Response> {\n if (!(response.headers.get('content-type') ?? '').includes('text/html')) {\n return response;\n }\n const html = injectLtRuntimeConfigScript(await response.text(), config, options);\n const headers = new Headers(response.headers);\n headers.delete('content-length');\n return new Response(html, { headers, status: response.status, statusText: response.statusText });\n}\n\n/**\n * The Angular render handler for `server.ts`: per request it reads the `NG_*` environment into an\n * {@link LtRequestContext}, renders with `engine.handle(req, context)`, adds the HTML cache headers and the runtime\n * config script, and writes the response. Unhandled requests go to `next()`.\n *\n * @example server.ts\n * app.use(ltAngularRequestHandler(new AngularNodeAppEngine(), { appVersion: packageJson.version }));\n */\nexport function ltAngularRequestHandler(engine: LtAngularEngine, options: LtAngularRequestHandlerOptions = {}): LtNodeMiddleware {\n return (req: IncomingMessage, res: ServerResponse, next) => {\n const context: LtRequestContext = readLtRequestContext(options.env, options);\n engine\n .handle(req, context)\n .then(async (response) => {\n if (!response) {\n next();\n return;\n }\n if (options.htmlNoCache !== false) {\n applyLtHtmlCacheHeaders(response);\n }\n await writeResponseToNodeResponse(await withLtRuntimeConfigScript(response, context.runtimeConfig, { submitGuard: options.submitGuard }), res);\n })\n .catch(next);\n };\n}\n","/// <reference types=\"node\" />\nimport { pipeline, Readable } from 'node:stream';\n\nimport { isLtSecureRequest, type LtNodeMiddleware } from './middlewares';\nimport { readLtRuntimeConfigFromEnv, type LtEnv } from './runtime-env';\n\n/** Options of {@link ltApiProxy}. */\nexport interface LtApiProxyOptions {\n /**\n * Serve the proxy (default: only when `NG_PUBLIC_API_PROXY=true`). On deployed stages the browser talks to the API\n * directly; the proxy is for same-origin cookies and WebAuthn on `localhost` (SSR dev server, `lt dev`, E2E).\n */\n enabled?: boolean;\n /** Environment (default `process.env`). */\n env?: LtEnv;\n /** Path prefix that is stripped (default `/api`). */\n prefix?: string;\n /** Target API (default `NG_API_URL`, then `NG_PUBLIC_API_URL`). */\n target?: string;\n}\n\nconst FORWARDED_REQUEST_HEADERS = [\n 'accept',\n 'accept-language',\n 'authorization',\n 'content-type',\n 'cookie',\n 'origin',\n 'referer',\n 'user-agent',\n 'x-file-id',\n 'x-system-setup-token',\n 'x-tenant-id',\n 'tus-resumable',\n 'upload-length',\n 'upload-metadata',\n 'upload-offset',\n 'upload-concat',\n 'upload-defer-length',\n];\nconst HOP_BY_HOP = new Set([\n 'connection',\n 'content-encoding',\n 'content-length',\n 'keep-alive',\n 'proxy-authenticate',\n 'proxy-authorization',\n 'te',\n 'trailer',\n 'transfer-encoding',\n 'upgrade',\n]);\n\n/**\n * Rewrite a backend `Set-Cookie` for the app origin: drop `Domain`, drop `Secure` on plain HTTP, force `Path=/`.\n * Without it the session cookie of `localhost:3000` never reaches the app on `localhost:3001`.\n */\nexport function rewriteLtProxyCookie(cookie: string, secure: boolean): string {\n const [pair = '', ...attributes] = cookie.split(';').map((part) => part.trim());\n const kept = attributes.filter((part) => part && !/^domain=/i.test(part) && !/^path=/i.test(part) && (secure || !/^secure$/i.test(part)));\n // Always `Path=/`: without one the browser scopes the cookie to the directory of the proxied URL (e.g. `/api/iam`).\n return [pair, 'Path=/', ...kept].join('; ');\n}\n\n/**\n * Rewrite a backend `Location` / `Content-Location` for the browser: a URL on the proxy target (`http://api:3000/tus/1`)\n * or an API path (`/tus/1`) becomes the proxied path (`/api/tus/1`); other origins (OAuth redirects) stay unchanged.\n * Without it a TUS upload continues against the internal `NG_API_URL`, which the browser can neither reach nor should\n * ever learn.\n */\nexport function rewriteLtProxyLocation(location: string, target: string, prefix: string): string {\n if (location.startsWith('/') && !location.startsWith('//')) {\n return `${prefix}${location}`;\n }\n try {\n const url = new URL(location);\n const base = new URL(target);\n if (url.origin !== base.origin) {\n return location;\n }\n const basePath = base.pathname.replace(/\\/+$/, '');\n const path = basePath && url.pathname.startsWith(`${basePath}/`) ? url.pathname.slice(basePath.length) : url.pathname;\n return `${prefix}${path}${url.search}${url.hash}`;\n } catch {\n return location;\n }\n}\n\n/**\n * Same-origin API proxy for the Angular SSR server: `/api/<path>` → `<target>/<path>` (method, body and the auth\n * headers forwarded, streaming both ways, `Set-Cookie` rewritten). The counterpart of nuxt-base-starter's\n * `server/api/iam/[...path].ts`, covering every API path (auth, TUS, AI SSE, sync).\n *\n * `ng serve` uses `proxy.conf.mjs` instead; this is for the built server (`.output/server/index.mjs`).\n */\nexport function ltApiProxy(options: LtApiProxyOptions = {}): LtNodeMiddleware {\n const prefix = (options.prefix ?? '/api').replace(/\\/+$/, '');\n return (req, res, next) => {\n const url = req.url ?? '';\n if (url !== prefix && !url.startsWith(`${prefix}/`) && !url.startsWith(`${prefix}?`)) {\n next();\n return;\n }\n const env = options.env ?? (globalThis as { process?: { env?: LtEnv } }).process?.env ?? {};\n const runtime = readLtRuntimeConfigFromEnv(env);\n const enabled = options.enabled ?? runtime.public.apiProxy === true;\n const target = (options.target ?? (runtime.serverApiUrl || runtime.public.apiUrl || '')).replace(/\\/+$/, '');\n if (!enabled || !target) {\n next();\n return;\n }\n const headers = new Headers();\n for (const name of FORWARDED_REQUEST_HEADERS) {\n const value = req.headers[name];\n if (value !== undefined) {\n headers.set(name, Array.isArray(value) ? value.join(', ') : value);\n }\n }\n const method = (req.method ?? 'GET').toUpperCase();\n const hasBody = method !== 'GET' && method !== 'HEAD';\n const controller = new AbortController();\n res.on('close', () => controller.abort());\n fetch(`${target}${url.slice(prefix.length) || '/'}`, {\n body: hasBody ? (Readable.toWeb(req) as unknown as BodyInit) : undefined,\n headers,\n method,\n redirect: 'manual',\n signal: controller.signal,\n ...(hasBody ? { duplex: 'half' } : {}),\n } as RequestInit)\n .then(async (response) => {\n res.statusCode = response.status;\n const secure = isLtSecureRequest(req);\n response.headers.forEach((value, name) => {\n if (name === 'location' || name === 'content-location') {\n res.setHeader(name, rewriteLtProxyLocation(value, target, prefix));\n } else if (!HOP_BY_HOP.has(name) && name !== 'set-cookie') {\n res.setHeader(name, value);\n }\n });\n const cookies = response.headers.getSetCookie?.() ?? [];\n if (cookies.length) {\n res.setHeader(\n 'set-cookie',\n cookies.map((cookie) => rewriteLtProxyCookie(cookie, secure)),\n );\n }\n if (!response.body) {\n res.end();\n return;\n }\n // pipeline(), not pipe(): a client that leaves mid-stream (SSE, AI stop, navigation) aborts the upstream body,\n // and that error must end this response instead of crashing the process as an unhandled 'error' event.\n pipeline(Readable.fromWeb(response.body as never), res, () => undefined);\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) {\n return;\n }\n // The cause may carry the internal NG_API_URL (e.g. \"Failed to parse URL from …\"): server log only.\n console.error('[@lenne.tech/ng-base/server] API proxy error:', error);\n res.statusCode = 502;\n res.setHeader('content-type', 'application/json');\n res.end(JSON.stringify({ message: 'API proxy error' }));\n });\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import { isPlatformBrowser } from "@angular/common";
2
+ import * as i0 from "@angular/core";
3
+ import { PLATFORM_ID, Service, inject } from "@angular/core";
4
+ import { LtI18nService, LtToastService } from "@lenne.tech/ng-base";
5
+ const LT_SHARE_MESSAGES = {
6
+ de: { lt: { "share": {
7
+ "copied": "Link kopiert",
8
+ "copiedDescription": "Der Link wurde in die Zwischenablage kopiert."
9
+ } } },
10
+ en: { lt: { "share": {
11
+ "copied": "Link copied",
12
+ "copiedDescription": "The link has been copied to clipboard."
13
+ } } }
14
+ };
15
+ function injectLtShareI18n() {
16
+ const i18n = inject(LtI18nService);
17
+ i18n.registerLibraryMessages("share", LT_SHARE_MESSAGES);
18
+ return i18n;
19
+ }
20
+ var LtShareService = class LtShareService {
21
+ i18n = injectLtShareI18n();
22
+ toast = inject(LtToastService);
23
+ isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
24
+ canShare() {
25
+ return this.isBrowser && typeof navigator !== "undefined" && typeof navigator.share === "function";
26
+ }
27
+ async share(title, text, url) {
28
+ if (!this.isBrowser) return "unavailable";
29
+ const target = url ?? globalThis.location?.href ?? "";
30
+ if (this.canShare()) try {
31
+ await navigator.share({
32
+ text: text ?? globalThis.location?.origin,
33
+ title,
34
+ url: target
35
+ });
36
+ return "shared";
37
+ } catch (error) {
38
+ if (error instanceof DOMException && error.name === "AbortError") return "aborted";
39
+ }
40
+ try {
41
+ await navigator.clipboard.writeText(target);
42
+ if (!this.toast.show({
43
+ color: "success",
44
+ description: this.i18n.t("lt.share.copiedDescription"),
45
+ title: this.i18n.t("lt.share.copied")
46
+ })) console.info(`[@lenne.tech/ng-base] ${this.i18n.t("lt.share.copied")}: ${target}`);
47
+ return "copied";
48
+ } catch {
49
+ return "failed";
50
+ }
51
+ }
52
+ static ɵfac = i0.ɵɵngDeclareFactory({
53
+ minVersion: "12.0.0",
54
+ version: "22.2.4",
55
+ ngImport: i0,
56
+ type: LtShareService,
57
+ deps: [],
58
+ target: i0.ɵɵFactoryTarget.Service
59
+ });
60
+ static ɵprov = i0.ɵɵngDeclareService({
61
+ minVersion: "22.0.0",
62
+ version: "22.2.4",
63
+ ngImport: i0,
64
+ type: LtShareService
65
+ });
66
+ };
67
+ i0.ɵɵngDeclareClassMetadata({
68
+ minVersion: "12.0.0",
69
+ version: "22.2.4",
70
+ ngImport: i0,
71
+ type: LtShareService,
72
+ decorators: [{ type: Service }]
73
+ });
74
+ export { LtShareService };
75
+
76
+ //# sourceMappingURL=lenne.tech-ng-base-share.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lenne.tech-ng-base-share.mjs","names":[],"sources":["../tmp-esm2022/share/lib/i18n/de.json","../tmp-esm2022/share/lib/i18n/en.json","../../../projects/ng-base/share/src/lib/i18n.ts","../../../projects/ng-base/share/src/lib/share-service.ts"],"sourcesContent":["","","import { inject } from '@angular/core';\nimport { LtI18nService } from '@lenne.tech/ng-base';\n\nimport de from './i18n/de.json';\nimport en from './i18n/en.json';\n\n/** The `lt.share.*` texts (also shipped as `i18n/share/{de,en}.json`). */\nexport const LT_SHARE_MESSAGES = { de, en } as const;\n\n/** `LtI18nService` with the `lt.share.*` texts registered (injection context). */\nexport function injectLtShareI18n(): LtI18nService {\n const i18n = inject(LtI18nService);\n i18n.registerLibraryMessages('share', LT_SHARE_MESSAGES);\n return i18n;\n}\n","import { isPlatformBrowser } from '@angular/common';\nimport { inject, PLATFORM_ID, Service } from '@angular/core';\nimport { LtToastService } from '@lenne.tech/ng-base';\nimport { injectLtShareI18n } from './i18n';\n\n/** Result of {@link LtShareService.share}. */\nexport type LtShareResult = 'aborted' | 'copied' | 'failed' | 'shared' | 'unavailable';\n\n/**\n * Web Share API with clipboard fallback (counterpart of `useLtShare()`). Browser only.\n *\n * `share()` uses `navigator.share({ title, text, url })` where available; otherwise the URL is copied to the clipboard\n * and a success toast (`lt.share.copied`) is shown. The URL defaults to the current page.\n */\n@Service()\nexport class LtShareService {\n private readonly i18n = injectLtShareI18n();\n private readonly toast = inject(LtToastService);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n /** Whether the native share sheet is available. */\n canShare(): boolean {\n return this.isBrowser && typeof navigator !== 'undefined' && typeof navigator.share === 'function';\n }\n\n /** Share a link (native share sheet, else clipboard + toast). */\n async share(title?: string, text?: string, url?: string): Promise<LtShareResult> {\n if (!this.isBrowser) {\n return 'unavailable';\n }\n const target = url ?? globalThis.location?.href ?? '';\n if (this.canShare()) {\n try {\n await navigator.share({ text: text ?? globalThis.location?.origin, title, url: target });\n return 'shared';\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n return 'aborted';\n }\n }\n }\n try {\n await navigator.clipboard.writeText(target);\n if (!this.toast.show({ color: 'success', description: this.i18n.t('lt.share.copiedDescription'), title: this.i18n.t('lt.share.copied') })) {\n console.info(`[@lenne.tech/ng-base] ${this.i18n.t('lt.share.copied')}: ${target}`);\n }\n return 'copied';\n } catch {\n return 'failed';\n }\n }\n}\n"],"mappings":";;;;AEOA,MAAa,oBAAoB;CAAE,IAAA,E;;;C,IAAA;CAAI,IAAA,E;;;C,IAAA;AAAE;AAGzC,SAAgB,oBAAiB;CAC/B,MAAM,OAAO,OAAO,aAAa;CACjC,KAAK,wBAAwB,SAAS,iBAAiB;CACvD,OAAO;AACT;ACCA,IAAa,iBAAb,MAAa,eAAc;CACR,OAAO,kBAAiB;CACxB,QAAQ,OAAO,cAAc;CAC7B,YAAY,kBAAkB,OAAO,WAAW,CAAC;CAGlE,WAAQ;EACN,OAAO,KAAK,aAAa,OAAO,cAAc,eAAe,OAAO,UAAU,UAAU;CAC1F;CAGA,MAAM,MAAM,OAAgB,MAAe,KAAY;EACrD,IAAI,CAAC,KAAK,WACR,OAAO;EAET,MAAM,SAAS,OAAO,WAAW,UAAU,QAAQ;EACnD,IAAI,KAAK,SAAQ,GACf,IAAI;GACF,MAAM,UAAU,MAAM;IAAE,MAAM,QAAQ,WAAW,UAAU;IAAQ;IAAO,KAAK;GAAM,CAAE;GACvF,OAAO;EACT,SAAS,OAAO;GACd,IAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAClD,OAAO;EAEX;EAEF,IAAI;GACF,MAAM,UAAU,UAAU,UAAU,MAAM;GAC1C,IAAI,CAAC,KAAK,MAAM,KAAK;IAAE,OAAO;IAAW,aAAa,KAAK,KAAK,EAAE,4BAA4B;IAAG,OAAO,KAAK,KAAK,EAAE,iBAAiB;GAAC,CAAE,GACtI,QAAQ,KAAK,yBAAyB,KAAK,KAAK,EAAE,iBAAiB,EAAC,IAAK,QAAQ;GAEnF,OAAO;EACT,QAAQ;GACN,OAAO;EACT;CACF;CAnCW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAd,OAAA,QAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;CAAc,CAAA;;AAAd,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAc,YAAA,CAAA,EAD1B,MAAA,Q"}