@saasicat/ui-vue 1.0.0-rc.2 → 1.0.0-rc.21

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 (309) hide show
  1. package/README.md +84 -19
  2. package/dist/.build-stamp +1 -1
  3. package/dist/assets/material-icons/material-icons.css +31 -0
  4. package/dist/assets/material-icons/web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff +0 -0
  5. package/dist/assets/material-icons/web-font/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2 +0 -0
  6. package/dist/assets/quasar.css +11696 -0
  7. package/dist/assets/ui-vue.css +6923 -0
  8. package/dist/auth/SuperAdminLoginPage.js +213 -0
  9. package/dist/auth/SuperAdminSetupWizard.js +5 -0
  10. package/dist/{batch-column-fetcher-VwjOxerL.d.ts → batch-column-fetcher-DQ89o95K.d.cts} +5 -5
  11. package/dist/{batch-column-fetcher-Dk9X92db.d.cts → batch-column-fetcher-Sr48UWEX.d.ts} +5 -5
  12. package/dist/{catalog-C5VKGbxk.d.cts → catalog-0eZwciPW.d.cts} +125 -86
  13. package/dist/{catalog-C5VKGbxk.d.ts → catalog-0eZwciPW.d.ts} +125 -86
  14. package/dist/{chunk-L7HPDVHV.js → chunk-47HDYN35.js} +86 -7
  15. package/dist/{chunk-A7JICGQ5.js → chunk-7CHT2ATN.js} +16 -3
  16. package/dist/{chunk-P4EJF43F.js → chunk-CZIVA536.js} +358 -300
  17. package/dist/{chunk-6X6AGH66.js → chunk-RFJ4UGOE.js} +7 -4
  18. package/dist/chunk-U7LNAX6T.js +35 -0
  19. package/dist/{chunk-4CJBABLZ.js → chunk-VLGEOPZH.js} +685 -196
  20. package/dist/chunks/AdminAccordion.vue_vue_type_script_setup_true_lang-DOwlTV5_.js +175 -0
  21. package/dist/chunks/AdminBanner.vue_vue_type_script_setup_true_lang-D27JEaak.js +83 -0
  22. package/dist/chunks/AdminBody.vue_vue_type_script_setup_true_lang-DxcVRzXE.js +41 -0
  23. package/dist/chunks/AdminDialog.vue_vue_type_script_setup_true_lang-CpxfSrx-.js +138 -0
  24. package/dist/chunks/AdminEmptyState.vue_vue_type_script_setup_true_lang-jaYkgNbE.js +48 -0
  25. package/dist/chunks/AdminErrorBanner.vue_vue_type_script_setup_true_lang-t-5uqt82.js +50 -0
  26. package/dist/chunks/AdminField.vue_vue_type_script_setup_true_lang-CtPByt2w.js +63 -0
  27. package/dist/chunks/AdminFieldGrid.vue_vue_type_script_setup_true_lang-BxuyHtBU.js +21 -0
  28. package/dist/chunks/AdminFilters.vue_vue_type_script_setup_true_lang-DSnzAlwj.js +18 -0
  29. package/dist/chunks/AdminFormDialog.vue_vue_type_script_setup_true_lang-BpWshaWv.js +84 -0
  30. package/dist/chunks/AdminHero.vue_vue_type_script_setup_true_lang-CoaRxXLF.js +46 -0
  31. package/dist/chunks/AdminKpi.vue_vue_type_script_setup_true_lang-CgCcGGmY.js +79 -0
  32. package/dist/chunks/AdminPage.vue_vue_type_script_setup_true_lang-L7St_zOY.js +15 -0
  33. package/dist/chunks/AdminPaginator.vue_vue_type_script_setup_true_lang-Cv8EEBGP.js +157 -0
  34. package/dist/chunks/AdminRefreshBtn.vue_vue_type_script_setup_true_lang-Bxk5GWOB.js +41 -0
  35. package/dist/chunks/AdminSection.vue_vue_type_script_setup_true_lang-DpjApOU-.js +62 -0
  36. package/dist/chunks/AdminStatistics.vue_vue_type_script_setup_true_lang-DwHeeYCX.js +32 -0
  37. package/dist/chunks/AdminStatusPill.vue_vue_type_script_setup_true_lang-09G3rCxN.js +32 -0
  38. package/dist/chunks/AdminTable.vue_vue_type_script_setup_true_lang-BzAusc-r.js +2007 -0
  39. package/dist/chunks/ClosePopup-iyFHWknU.js +48 -0
  40. package/dist/chunks/PromoCodeEditDialog.vue_vue_type_script_setup_true_lang-NiW-Ky7H.js +639 -0
  41. package/dist/chunks/QBadge-B8LYhEVv.js +43 -0
  42. package/dist/chunks/QBtn-CSVcAwrE.js +770 -0
  43. package/dist/chunks/QCard-g0Hwqx6i.js +30 -0
  44. package/dist/chunks/QCardSection-FvPMZdQ4.js +22 -0
  45. package/dist/chunks/QCheckbox-BwxH7EyE.js +63 -0
  46. package/dist/chunks/QDialog-CcwVEueo.js +331 -0
  47. package/dist/chunks/QIcon-DaxYRLz0.js +195 -0
  48. package/dist/chunks/QInput-SRRCebo8.js +1663 -0
  49. package/dist/chunks/QItem-DunhGoPO.js +127 -0
  50. package/dist/chunks/QList-D3jMUITp.js +37 -0
  51. package/dist/chunks/QMenu-BFP-qtEm.js +831 -0
  52. package/dist/chunks/QSelect-jOvICNCy.js +1885 -0
  53. package/dist/chunks/QSeparator-CrLemO5z.js +60 -0
  54. package/dist/chunks/QSpinner-DblEBRSQ.js +57 -0
  55. package/dist/chunks/QToggle-BBogOutP.js +40 -0
  56. package/dist/chunks/QTooltip-Ch_r2hMZ.js +320 -0
  57. package/dist/chunks/SuperAdminSetupWizard-UO4j4Eyu.js +465 -0
  58. package/dist/chunks/TenantActionConfirmDialog-DU11RlmB.js +201 -0
  59. package/dist/chunks/_plugin-vue_export-helper-1tPrXgE0.js +10 -0
  60. package/dist/chunks/catalog-i18n-tKlkm6-2.js +32 -0
  61. package/dist/chunks/create-Ck-e8kVF.js +42 -0
  62. package/dist/chunks/detached-fullscreen-DuM-R9uv.js +488 -0
  63. package/dist/chunks/focus-manager-Cc4uTjsQ.js +301 -0
  64. package/dist/chunks/format-BIQKj_qk.js +23 -0
  65. package/dist/chunks/is-DNOHJAOK.js +269 -0
  66. package/dist/chunks/plan-area-context-RiY4rHni.js +20 -0
  67. package/dist/chunks/private.use-form-BdJSI6of.js +30 -0
  68. package/dist/chunks/render-DSsuXum_.js +32 -0
  69. package/dist/chunks/symbols-Cy0ehVpr.js +67 -0
  70. package/dist/chunks/touch-B8tpYG34.js +162 -0
  71. package/dist/chunks/use-checkbox-CBtmpkdc.js +221 -0
  72. package/dist/chunks/use-dark-VmDF1SYZ.js +14 -0
  73. package/dist/chunks/use-hydration-PO-eh3w4.js +14 -0
  74. package/dist/chunks/use-prevent-scroll-B9A_pIzH.js +156 -0
  75. package/dist/chunks/use-render-cache-Bj5SbY5v.js +22 -0
  76. package/dist/chunks/use-size-C7KmPm4L.js +23 -0
  77. package/dist/chunks/vm-Dl-TBfKC.js +182 -0
  78. package/dist/client/index.cjs +488 -306
  79. package/dist/client/index.d.cts +107 -7
  80. package/dist/client/index.d.ts +107 -7
  81. package/dist/client/index.js +25 -3
  82. package/dist/index.cjs +1226 -536
  83. package/dist/index.d.cts +5 -5
  84. package/dist/index.d.ts +5 -5
  85. package/dist/index.js +53 -7
  86. package/dist/layouts/AdminLayout.js +1711 -0
  87. package/dist/pages/AdminManifestErrorPage.js +99 -0
  88. package/dist/pages/AuditPage.js +244 -0
  89. package/dist/pages/BundlesPage.js +2883 -0
  90. package/dist/pages/DashboardPage.js +299 -0
  91. package/dist/pages/DiscoveryPage.js +2563 -0
  92. package/dist/pages/EmailHistoryPage.js +509 -0
  93. package/dist/pages/MarketingCatalogPage.js +2095 -0
  94. package/dist/pages/PilotsPage.js +1197 -0
  95. package/dist/pages/PlanReviewPage.js +563 -0
  96. package/dist/pages/PlanVersionEditorPage.js +1626 -0
  97. package/dist/pages/PlansPage.js +6164 -0
  98. package/dist/pages/PlatformEmailPage.js +455 -0
  99. package/dist/pages/PromoCodeDetailPage.js +240 -0
  100. package/dist/pages/PromoCodesPage.js +567 -0
  101. package/dist/pages/SettingsPage.js +216 -0
  102. package/dist/pages/SubscriptionsPage.js +113 -0
  103. package/dist/pages/TenantDetailPage.js +393 -0
  104. package/dist/pages/TenantsPage.js +430 -0
  105. package/dist/pages/UsersPage.js +386 -0
  106. package/dist/pages/index.js +75 -0
  107. package/dist/quasar/index.cjs +388 -297
  108. package/dist/quasar/index.d.cts +13 -3
  109. package/dist/quasar/index.d.ts +13 -3
  110. package/dist/quasar/index.js +10 -6
  111. package/dist/{resource-registry-CrHUvVx6.d.cts → resource-registry-GAxu2kn6.d.ts} +32 -18
  112. package/dist/{resource-registry-Cw_c0F11.d.ts → resource-registry-zfCLvEgx.d.cts} +32 -18
  113. package/dist/testing/admin-pages-suite.cjs +4 -1
  114. package/dist/testing/admin-pages-suite.d.cts +10 -1
  115. package/dist/testing/admin-pages-suite.d.ts +10 -1
  116. package/dist/testing/admin-pages-suite.js +3 -1
  117. package/dist/testing/mount-with-quasar.cjs +65 -0
  118. package/dist/testing/mount-with-quasar.d.cts +7 -0
  119. package/dist/testing/mount-with-quasar.d.ts +7 -0
  120. package/dist/testing/mount-with-quasar.js +63 -0
  121. package/dist/ui/data/AdminKpi.js +4 -0
  122. package/dist/ui/data/AdminPaginator.js +4 -0
  123. package/dist/ui/data/AdminRowActions.js +37 -0
  124. package/dist/ui/data/AdminStatistics.js +4 -0
  125. package/dist/ui/data/AdminStatusPill.js +4 -0
  126. package/dist/ui/data/AdminTable.js +4 -0
  127. package/dist/ui/data/KvBlock.js +24 -0
  128. package/dist/ui/entitlement/FeatureGate.js +25 -0
  129. package/dist/ui/feedback/AdminBanner.js +4 -0
  130. package/dist/ui/feedback/AdminEmptyState.js +4 -0
  131. package/dist/ui/feedback/AdminErrorBanner.js +4 -0
  132. package/dist/ui/feedback/AdminRefreshBtn.js +4 -0
  133. package/dist/ui/overlay/AdminConfirmDialog.js +112 -0
  134. package/dist/ui/overlay/AdminDialog.js +4 -0
  135. package/dist/ui/overlay/AdminFormDialog.js +4 -0
  136. package/dist/ui/overlay/MfaPromptDialog.js +131 -0
  137. package/dist/ui/page/AdminAccordion.js +4 -0
  138. package/dist/ui/page/AdminBody.js +4 -0
  139. package/dist/ui/page/AdminField.js +4 -0
  140. package/dist/ui/page/AdminFieldGrid.js +4 -0
  141. package/dist/ui/page/AdminFilters.js +4 -0
  142. package/dist/ui/page/AdminHero.js +4 -0
  143. package/dist/ui/page/AdminPage.js +4 -0
  144. package/dist/ui/page/AdminSection.js +4 -0
  145. package/dist/ui/page/AdminToolbar.js +35 -0
  146. package/dist/ui/page/LocaleSwitcher.js +90 -0
  147. package/dist/ui/page/ThemeSwitcher.js +95 -0
  148. package/dist/ui/page/WizardStepper.js +55 -0
  149. package/dist/vue/index.cjs +1135 -524
  150. package/dist/vue/index.d.cts +520 -44
  151. package/dist/vue/index.d.ts +520 -44
  152. package/dist/vue/index.js +30 -6
  153. package/package.json +30 -15
  154. package/src/auth/SuperAdminLoginPage.vue +16 -16
  155. package/src/auth/SuperAdminSetupWizard.vue +33 -28
  156. package/src/client/admin-resource-client.ts +23 -8
  157. package/src/client/billing-area.ts +14 -0
  158. package/src/client/brand-bridge.ts +98 -0
  159. package/src/client/http/axios-http-client.ts +4 -3
  160. package/src/client/http-json.ts +16 -3
  161. package/src/client/i18n/messages/audit.ts +1 -0
  162. package/src/client/i18n/messages/bundles.ts +17 -4
  163. package/src/client/i18n/messages/common.ts +1 -0
  164. package/src/client/i18n/messages/dashboard.ts +1 -0
  165. package/src/client/i18n/messages/discovery.ts +10 -19
  166. package/src/client/i18n/messages/email.ts +1 -0
  167. package/src/client/i18n/messages/errors.ts +1 -0
  168. package/src/client/i18n/messages/marketing.ts +7 -2
  169. package/src/client/i18n/messages/nav.ts +3 -0
  170. package/src/client/i18n/messages/pilots.ts +1 -0
  171. package/src/client/i18n/messages/plan-detail.ts +1 -0
  172. package/src/client/i18n/messages/plan-editor.ts +1 -0
  173. package/src/client/i18n/messages/plan-versions.ts +3 -4
  174. package/src/client/i18n/messages/plans.ts +9 -4
  175. package/src/client/i18n/messages/promos.ts +3 -0
  176. package/src/client/i18n/messages/settings.ts +75 -0
  177. package/src/client/i18n/messages/shell.ts +1 -0
  178. package/src/client/i18n/messages/tenants.ts +1 -0
  179. package/src/client/i18n/messages/users.ts +1 -0
  180. package/src/client/i18n/messages.ts +3 -0
  181. package/src/client/index.ts +10 -0
  182. package/src/client/mfa-header.ts +14 -0
  183. package/src/client/nav-builder.ts +7 -4
  184. package/src/client/reorder-priorities.ts +76 -0
  185. package/src/client/resources/bundles.resource.ts +24 -38
  186. package/src/client/resources/catalog.resource.ts +91 -113
  187. package/src/client/resources/define-resource.ts +2 -75
  188. package/src/client/resources/index.ts +3 -0
  189. package/src/client/resources/marketing.resource.ts +77 -80
  190. package/src/client/resources/pilots.resource.ts +1 -11
  191. package/src/client/resources/plans.resource.ts +47 -64
  192. package/src/client/resources/platform-email.resource.ts +1 -11
  193. package/src/client/resources/promotions.resource.ts +18 -25
  194. package/src/client/resources/settings.resource.ts +68 -0
  195. package/src/client/resources/tenants.resource.ts +10 -4
  196. package/src/client/resources/users.resource.ts +3 -2
  197. package/src/client/settings-view.ts +50 -0
  198. package/src/client/version-change-fields.ts +17 -0
  199. package/src/features/bundle/BundleVersionInlineEditor.vue +112 -155
  200. package/src/features/bundle/BundleVersionPublishDialog.vue +34 -16
  201. package/src/features/bundle/BundleVersionStrip.vue +25 -31
  202. package/src/features/bundle/VersionDiffPreview.vue +21 -15
  203. package/src/features/bundle/internal/BundleCreatePanel.vue +65 -119
  204. package/src/features/bundle/internal/BundleFeaturesEditor.vue +18 -31
  205. package/src/features/bundle/internal/BundlePlanCompatPicker.vue +23 -29
  206. package/src/features/bundle/internal/BundleQuotasEditor.vue +20 -41
  207. package/src/features/bundle/internal/BundleStatusBanner.vue +16 -70
  208. package/src/features/marketing/MarketingPromotionsTab.vue +155 -122
  209. package/src/features/plan/PlanCreateDialog.vue +49 -129
  210. package/src/features/plan/PlanDetail.vue +57 -76
  211. package/src/features/plan/PlanList.vue +81 -156
  212. package/src/features/plan/PlanMatrix.vue +89 -158
  213. package/src/features/plan/PlanReview.vue +62 -80
  214. package/src/features/plan/PlanVersionEditor.vue +134 -238
  215. package/src/features/plan/internal/PlanCatalogPreview.vue +22 -68
  216. package/src/features/plan/internal/PlanComponentPool.vue +18 -88
  217. package/src/features/plan/internal/PlanTitleEdit.vue +12 -9
  218. package/src/features/plan/internal/PlanVersionBasket.vue +65 -89
  219. package/src/features/plan/internal/PlanVersionEditorHeader.vue +16 -20
  220. package/src/features/plan/internal/PlanVersionsPanel.vue +29 -75
  221. package/src/features/tenant/TenantActionConfirmDialog.vue +4 -4
  222. package/src/index.ts +9 -0
  223. package/src/internal/bundles-page/BundleAccordionList.vue +32 -2
  224. package/src/internal/bundles-page/BundleDetailPanel.vue +37 -21
  225. package/src/internal/bundles-page/BundlesToolbar.vue +9 -5
  226. package/src/internal/dialogs/PilotCreateDialog.vue +65 -104
  227. package/src/internal/dialogs/PilotEditDialog.vue +22 -23
  228. package/src/internal/dialogs/PromoCodeCreateDialog.vue +27 -23
  229. package/src/internal/dialogs/PromoCodeDialogFields.vue +203 -252
  230. package/src/internal/dialogs/PromoCodeEditDialog.vue +52 -48
  231. package/src/internal/dialogs/pilot-dialog.css +16 -111
  232. package/src/internal/discovery-page/CatalogEntryTransPanel.vue +18 -18
  233. package/src/internal/discovery-page/DiscoveryCapList.vue +20 -20
  234. package/src/internal/discovery-page/DiscoveryFeatureCard.vue +20 -20
  235. package/src/internal/discovery-page/DiscoveryQuotaCard.vue +10 -10
  236. package/src/internal/discovery-page/DiscoveryStatusControl.vue +1 -1
  237. package/src/internal/marketing-catalog-page/MarketingCatalogAdmin.vue +660 -0
  238. package/src/internal/{marketing-catalog → marketing-catalog-page}/MarketingCatalogHeader.vue +21 -16
  239. package/src/internal/{marketing-catalog → marketing-catalog-page}/MarketingCatalogPreview.vue +26 -13
  240. package/src/internal/{marketing-catalog → marketing-catalog-page}/MarketingCatalogToolbar.vue +14 -10
  241. package/src/internal/plan-versions/PlanDiffCard.vue +15 -15
  242. package/src/internal/plan-versions/PlanVersionsDiff.vue +11 -11
  243. package/src/internal/plan-versions/PlanVersionsTimeline.vue +35 -31
  244. package/src/internal/plans-page/PlanBundleOverview.vue +8 -8
  245. package/src/internal/plans-page/PlanPublishDialog.vue +2 -2
  246. package/src/internal/tenant-detail/TenantUsage.vue +3 -3
  247. package/src/internal/tenant-detail/types.ts +2 -2
  248. package/src/layouts/AdminLayout.vue +22 -22
  249. package/src/pages/AdminManifestErrorPage.vue +7 -7
  250. package/src/pages/AuditPage.vue +2 -2
  251. package/src/pages/BundlesPage.vue +81 -89
  252. package/src/pages/DashboardPage.vue +106 -97
  253. package/src/pages/DiscoveryPage.vue +22 -28
  254. package/src/pages/EmailHistoryPage.vue +26 -34
  255. package/src/pages/MarketingCatalogPage.vue +289 -281
  256. package/src/pages/PilotsPage.vue +22 -35
  257. package/src/pages/PlanVersionEditorPage.vue +1 -1
  258. package/src/pages/PlansPage.vue +181 -107
  259. package/src/pages/PlatformEmailPage.vue +33 -41
  260. package/src/pages/PromoCodeDetailPage.vue +12 -18
  261. package/src/pages/PromoCodesPage.vue +36 -14
  262. package/src/pages/SettingsPage.vue +226 -0
  263. package/src/pages/TenantDetailPage.vue +28 -53
  264. package/src/pages/TenantsPage.vue +7 -7
  265. package/src/pages/UsersPage.vue +7 -20
  266. package/src/pages/index.ts +3 -1
  267. package/src/quasar/create-super-admin-app.ts +13 -2
  268. package/src/quasar/dark-bridge.ts +8 -4
  269. package/src/quasar/index.ts +11 -0
  270. package/src/testing/admin-pages-suite.ts +11 -1
  271. package/src/testing/mount-with-quasar.ts +73 -0
  272. package/src/ui/data/AdminPaginator.vue +30 -20
  273. package/src/ui/data/KvBlock.vue +4 -4
  274. package/src/ui/entitlement/FeatureGate.vue +2 -2
  275. package/src/ui/feedback/AdminRefreshBtn.vue +10 -7
  276. package/src/ui/overlay/MfaPromptDialog.vue +5 -6
  277. package/src/ui/page/AdminAccordion.vue +27 -10
  278. package/src/ui/page/WizardStepper.vue +7 -18
  279. package/src/ui/theme/base.css +31 -0
  280. package/src/ui/theme/components/accordion.css +9 -9
  281. package/src/ui/theme/components/button.css +10 -68
  282. package/src/ui/theme/components/card.css +0 -8
  283. package/src/ui/theme/components/paginator.css +14 -28
  284. package/src/ui/theme/tokens.semantic.dark.css +13 -0
  285. package/src/ui/theme/tokens.semantic.light.css +39 -0
  286. package/src/vue/index.ts +9 -0
  287. package/src/vue/platform-loaders.ts +1 -3
  288. package/src/vue/resource-registry.ts +0 -8
  289. package/src/vue/super-admin-context.ts +14 -15
  290. package/src/vue/use-applied-settings.ts +79 -0
  291. package/src/vue/use-bulk-publish.ts +2 -5
  292. package/src/vue/use-bundles.ts +6 -10
  293. package/src/vue/use-catalog-entries.ts +9 -16
  294. package/src/vue/use-dialog.ts +221 -0
  295. package/src/vue/use-marketing-projections.ts +5 -6
  296. package/src/vue/use-mfa-prompt.ts +61 -11
  297. package/src/vue/use-plans.ts +28 -21
  298. package/src/vue/use-promotions.ts +1 -7
  299. package/src/vue/use-row-reorder.ts +109 -0
  300. package/src/vue/use-sa-theme.ts +31 -0
  301. package/src/vue/use-steps.ts +109 -0
  302. package/src/vue/use-subscription-draft.ts +63 -60
  303. package/src/vue/use-tenant-billing-details.ts +119 -0
  304. package/src/vue/use-tenant-billing.ts +250 -33
  305. package/src/vue/use-tenant-payment-method.ts +112 -0
  306. package/src/vue/use-tenant-subscription-bundles.ts +8 -0
  307. package/src/internal/marketing-catalog/MarketingCatalogAdmin.vue +0 -553
  308. package/src/internal/plans-page/PlansPageToast.vue +0 -69
  309. /package/src/internal/{marketing-catalog → marketing-catalog-page}/types.ts +0 -0
@@ -1,9 +1,3 @@
1
- // src/client/i18n/format.ts
2
- import { formatErrorMessage } from "@saasicat/core";
3
- function formatMessage(template, params) {
4
- return formatErrorMessage(template, params);
5
- }
6
-
7
1
  // src/client/attach-cause.ts
8
2
  function attachCause(error, cause) {
9
3
  Object.defineProperty(error, "cause", {
@@ -14,6 +8,12 @@ function attachCause(error, cause) {
14
8
  return error;
15
9
  }
16
10
 
11
+ // src/client/i18n/format.ts
12
+ import { formatErrorMessage } from "@saasicat/core";
13
+ function formatMessage(template, params) {
14
+ return formatErrorMessage(template, params);
15
+ }
16
+
17
17
  // src/client/admin-error.ts
18
18
  var ADMIN_ERROR = /* @__PURE__ */ Symbol.for("saasicat/ui-vue/AdminError");
19
19
  var PLATFORM_ERROR = /* @__PURE__ */ Symbol.for("saasicat/ui-vue/PlatformError");
@@ -253,14 +253,20 @@ async function getJson(http, url) {
253
253
  }
254
254
  return await res.json();
255
255
  }
256
- async function postJson(http, url, body) {
256
+ function postJson(http, url, body) {
257
+ return sendJson(http, "POST", url, body);
258
+ }
259
+ function patchJson(http, url, body) {
260
+ return sendJson(http, "PATCH", url, body);
261
+ }
262
+ async function sendJson(http, method, url, body) {
257
263
  const res = await http(url, {
258
- method: "POST",
264
+ method,
259
265
  headers: { "Content-Type": "application/json" },
260
266
  body: JSON.stringify(body)
261
267
  });
262
268
  if (res.status < 200 || res.status >= 300) {
263
- throw await failed(res, "POST", url);
269
+ throw await failed(res, method, url);
264
270
  }
265
271
  return await res.json();
266
272
  }
@@ -340,26 +346,14 @@ function defaultHttpClient() {
340
346
  }
341
347
 
342
348
  // src/client/resources/define-resource.ts
343
- function defineResource(key, ops, options = {}) {
344
- return { key, ops, projectScoped: options.projectScoped ?? false };
345
- }
346
- function requireProjectKey(def, ctx) {
347
- if (!def.projectScoped) return;
348
- if (typeof ctx.projectKey === "string" && ctx.projectKey.trim() !== "") return;
349
- throw new Error(
350
- `Resource "${def.key}" is project-scoped, but the context it is bound to names no project. Its requests would go out as \`?projectKey=\`, which the admin API answers for no project at all: the catalogue reads as empty and the first create fails validation instead. Name the project this admin administers \u2014 \`endpoints.projectKey\` for createSuperAdminApp(), \`context.projectKey\` for createResourceRegistry().`
351
- );
349
+ function defineResource(key, ops) {
350
+ return { key, ops };
352
351
  }
353
352
  function bindResource(def, http, ctx) {
354
353
  const readContext = typeof ctx === "function" ? ctx : () => ctx;
355
- if (def.projectScoped) requireProjectKey(def, readContext());
356
354
  const bound = {};
357
355
  for (const [name, op] of Object.entries(def.ops)) {
358
- bound[name] = async (...args) => {
359
- const context = readContext();
360
- requireProjectKey(def, context);
361
- return op(http, context, ...args);
362
- };
356
+ bound[name] = async (...args) => op(http, readContext(), ...args);
363
357
  }
364
358
  return bound;
365
359
  }
@@ -463,6 +457,12 @@ function defineListOp(endpoint) {
463
457
  return async (http, ctx, query) => readListPage(await requestJson(http, listUrl(endpoint(ctx), query)));
464
458
  }
465
459
 
460
+ // src/client/mfa-header.ts
461
+ var MFA_CODE_HEADER = "X-Mfa-Code";
462
+ function mfaHeader(mfaCode) {
463
+ return mfaCode ? { [MFA_CODE_HEADER]: mfaCode } : void 0;
464
+ }
465
+
466
466
  // src/client/resources/plans.resource.ts
467
467
  function plansUrl(ctx) {
468
468
  return `${ctx.apiBase}/catalog/plans`;
@@ -470,50 +470,32 @@ function plansUrl(ctx) {
470
470
  function versionsUrl(ctx) {
471
471
  return `${ctx.apiBase}/catalog/plan-versions`;
472
472
  }
473
- function scoped(url, ctx) {
474
- return `${url}?projectKey=${encodeURIComponent(ctx.projectKey)}`;
475
- }
476
- var plansResource = defineResource(
477
- "plans",
478
- {
479
- list: async (http, ctx) => await requestJson(http, scoped(plansUrl(ctx), ctx)) ?? [],
480
- tenantCounts: async (http, ctx) => await requestJson(
481
- http,
482
- scoped(`${plansUrl(ctx)}/tenant-counts`, ctx)
483
- ) ?? {},
484
- /**
485
- * The project comes from the context, not from the caller.
486
- *
487
- * The endpoint takes it in the body, and the composable this replaces
488
- * made that the caller's job — so a page had to keep hold of the
489
- * project it was administering just to create in it, and `list()` and
490
- * `create()` read two different sources for one value. A stale one
491
- * creates a plan outside the project the list is showing.
492
- */
493
- create: (http, ctx, data) => requestJsonBody(http, plansUrl(ctx), "Create returned no body", {
494
- method: "POST",
495
- body: { ...data, projectKey: ctx.projectKey }
496
- }),
497
- update: (http, ctx, planId, data) => requestJsonBody(
498
- http,
499
- `${plansUrl(ctx)}/${planId}`,
500
- "Update returned no body",
501
- {
502
- method: "PATCH",
503
- body: data
504
- }
505
- ),
506
- /** Marks the plan deleted. Fails while it still has versions. */
507
- softDelete: async (http, ctx, planId) => {
508
- await requestJson(http, `${plansUrl(ctx)}/${planId}`, { method: "DELETE" });
509
- },
510
- /** Removes the plan for good. 422 `PLAN_HAS_VERSIONS` when it cannot. */
511
- hardDelete: async (http, ctx, planId) => {
512
- await requestJson(http, `${plansUrl(ctx)}/${planId}/purge`, { method: "DELETE" });
513
- }
473
+ var plansResource = defineResource("plans", {
474
+ list: async (http, ctx) => await requestJson(http, plansUrl(ctx)) ?? [],
475
+ tenantCounts: async (http, ctx) => await requestJson(http, `${plansUrl(ctx)}/tenant-counts`) ?? {},
476
+ create: (http, ctx, data) => requestJsonBody(http, plansUrl(ctx), "Create returned no body", {
477
+ method: "POST",
478
+ body: data
479
+ }),
480
+ update: (http, ctx, planId, data) => requestJsonBody(http, `${plansUrl(ctx)}/${planId}`, "Update returned no body", {
481
+ method: "PATCH",
482
+ body: data
483
+ }),
484
+ /** Marks the plan deleted. Fails while it still has versions. */
485
+ softDelete: async (http, ctx, planId) => {
486
+ await requestJson(http, `${plansUrl(ctx)}/${planId}`, { method: "DELETE" });
514
487
  },
515
- { projectScoped: true }
516
- );
488
+ /**
489
+ * Removes the plan for good. 422 `PLAN_HAS_VERSIONS` when it cannot. The
490
+ * route requires the second factor.
491
+ */
492
+ hardDelete: async (http, ctx, planId, mfaCode) => {
493
+ await requestJson(http, `${plansUrl(ctx)}/${planId}/purge`, {
494
+ method: "DELETE",
495
+ headers: mfaHeader(mfaCode)
496
+ });
497
+ }
498
+ });
517
499
  var planVersionsResource = defineResource("planVersions", {
518
500
  listForPlan: async (http, ctx, planId) => await requestJson(http, `${plansUrl(ctx)}/${planId}/versions`) ?? [],
519
501
  createDraft: (http, ctx, planId, data) => requestJsonBody(
@@ -528,11 +510,12 @@ var planVersionsResource = defineResource("planVersions", {
528
510
  "UpdateDraft returned no body",
529
511
  { method: "PATCH", body: data }
530
512
  ),
531
- publish: (http, ctx, versionId, options = {}) => requestJsonBody(
513
+ /** Puts a draft live. The route requires the second factor. */
514
+ publish: (http, ctx, versionId, options = {}, mfaCode) => requestJsonBody(
532
515
  http,
533
516
  `${versionsUrl(ctx)}/${versionId}/publish`,
534
517
  "Publish returned no body",
535
- { method: "POST", body: options }
518
+ { method: "POST", body: options, headers: mfaHeader(mfaCode) }
536
519
  ),
537
520
  discardDraft: async (http, ctx, versionId) => {
538
521
  await requestJson(http, `${versionsUrl(ctx)}/${versionId}`, { method: "DELETE" });
@@ -543,12 +526,13 @@ var planVersionsResource = defineResource("planVersions", {
543
526
  *
544
527
  * `endsAt` is the date itself, not a payload: the endpoint's body is
545
528
  * `{ endsAt }` and wrapping it is this operation's job, not the caller's.
529
+ * The route requires the second factor.
546
530
  */
547
- terminate: (http, ctx, versionId, endsAt) => requestJsonBody(
531
+ terminate: (http, ctx, versionId, endsAt, mfaCode) => requestJsonBody(
548
532
  http,
549
533
  `${versionsUrl(ctx)}/${versionId}/terminate`,
550
534
  "Terminate returned no body",
551
- { method: "POST", body: { endsAt } }
535
+ { method: "POST", body: { endsAt }, headers: mfaHeader(mfaCode) }
552
536
  )
553
537
  });
554
538
 
@@ -559,30 +543,23 @@ function bundlesUrl(ctx) {
559
543
  function bundleVersionsUrl(ctx) {
560
544
  return `${ctx.apiBase}/catalog/bundle-versions`;
561
545
  }
562
- function scoped2(url, ctx) {
563
- return `${url}?projectKey=${encodeURIComponent(ctx.projectKey)}`;
564
- }
565
- var bundlesResource = defineResource(
566
- "bundles",
567
- {
568
- list: async (http, ctx) => await requestJson(http, scoped2(bundlesUrl(ctx), ctx)) ?? [],
569
- create: (http, ctx, data) => requestJsonBody(http, bundlesUrl(ctx), "Create returned no body", {
570
- method: "POST",
571
- body: { ...data, projectKey: ctx.projectKey }
572
- }),
573
- update: (http, ctx, bundleId, data) => requestJsonBody(
574
- http,
575
- `${bundlesUrl(ctx)}/${bundleId}`,
576
- "Update returned no body",
577
- { method: "PATCH", body: data }
578
- ),
579
- /** Marks the bundle deleted. */
580
- softDelete: async (http, ctx, bundleId) => {
581
- await requestJson(http, `${bundlesUrl(ctx)}/${bundleId}`, { method: "DELETE" });
582
- }
583
- },
584
- { projectScoped: true }
585
- );
546
+ var bundlesResource = defineResource("bundles", {
547
+ list: async (http, ctx) => await requestJson(http, bundlesUrl(ctx)) ?? [],
548
+ create: (http, ctx, data) => requestJsonBody(http, bundlesUrl(ctx), "Create returned no body", {
549
+ method: "POST",
550
+ body: data
551
+ }),
552
+ update: (http, ctx, bundleId, data) => requestJsonBody(
553
+ http,
554
+ `${bundlesUrl(ctx)}/${bundleId}`,
555
+ "Update returned no body",
556
+ { method: "PATCH", body: data }
557
+ ),
558
+ /** Marks the bundle deleted. */
559
+ softDelete: async (http, ctx, bundleId) => {
560
+ await requestJson(http, `${bundlesUrl(ctx)}/${bundleId}`, { method: "DELETE" });
561
+ }
562
+ });
586
563
  var bundleVersionsResource = defineResource("bundleVersions", {
587
564
  listForBundle: async (http, ctx, bundleId) => await requestJson(http, `${bundlesUrl(ctx)}/${bundleId}/versions`) ?? [],
588
565
  createDraft: (http, ctx, bundleId, data) => requestJsonBody(
@@ -597,11 +574,12 @@ var bundleVersionsResource = defineResource("bundleVersions", {
597
574
  "UpdateDraft returned no body",
598
575
  { method: "PATCH", body: data }
599
576
  ),
600
- publish: (http, ctx, versionId, options = {}) => requestJsonBody(
577
+ /** Puts a draft live. The route requires the second factor. */
578
+ publish: (http, ctx, versionId, options = {}, mfaCode) => requestJsonBody(
601
579
  http,
602
580
  `${bundleVersionsUrl(ctx)}/${versionId}/publish`,
603
581
  "Publish returned no body",
604
- { method: "POST", body: options }
582
+ { method: "POST", body: options, headers: mfaHeader(mfaCode) }
605
583
  ),
606
584
  /**
607
585
  * Discards a draft. A published version cannot be discarded — the API
@@ -616,78 +594,62 @@ var bundleVersionsResource = defineResource("bundleVersions", {
616
594
  function catalogUrl(ctx) {
617
595
  return `${ctx.apiBase}/catalog`;
618
596
  }
619
- function scoped3(url, ctx) {
620
- return `${url}?projectKey=${encodeURIComponent(ctx.projectKey)}`;
621
- }
622
- var catalogResource = defineResource(
623
- "catalog",
624
- {
625
- capabilities: async (http, ctx) => await requestJson(
626
- http,
627
- scoped3(`${catalogUrl(ctx)}/capabilities`, ctx)
628
- ) ?? [],
629
- features: async (http, ctx) => await requestJson(
630
- http,
631
- scoped3(`${catalogUrl(ctx)}/features`, ctx)
632
- ) ?? [],
633
- quotas: async (http, ctx) => await requestJson(
634
- http,
635
- scoped3(`${catalogUrl(ctx)}/quotas`, ctx)
636
- ) ?? [],
637
- reviewFeature: (http, ctx, featureKey, data) => requestJsonBody(
638
- http,
639
- scoped3(`${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}/review`, ctx),
640
- "Review returned no body",
641
- { method: "PATCH", body: data }
642
- ),
643
- reviewQuota: (http, ctx, quotaKey, data) => requestJsonBody(
644
- http,
645
- scoped3(`${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}/review`, ctx),
646
- "Review returned no body",
647
- { method: "PATCH", body: data }
648
- ),
649
- /** The translations are wrapped in `{ i18n }` here, not by the caller. */
650
- setFeatureI18n: (http, ctx, featureKey, i18n) => requestJsonBody(
651
- http,
652
- scoped3(`${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}/i18n`, ctx),
653
- "i18n returned no body",
654
- { method: "PATCH", body: { i18n } }
655
- ),
656
- setQuotaI18n: (http, ctx, quotaKey, i18n) => requestJsonBody(
657
- http,
658
- scoped3(`${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}/i18n`, ctx),
659
- "i18n returned no body",
660
- { method: "PATCH", body: { i18n } }
661
- ),
662
- setFeatureBase: (http, ctx, featureKey, data) => requestJsonBody(
663
- http,
664
- scoped3(`${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}`, ctx),
665
- "Base returned no body",
666
- { method: "PATCH", body: data }
667
- ),
668
- setQuotaBase: (http, ctx, quotaKey, data) => requestJsonBody(
669
- http,
670
- scoped3(`${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}`, ctx),
671
- "Base returned no body",
672
- { method: "PATCH", body: data }
673
- ),
674
- /**
675
- * Writes a discovery snapshot into the catalogue.
676
- *
677
- * The request only. `useCatalogEntries.syncDiscovery` reloads the three
678
- * lists afterwards, which is that composable keeping its refs true —
679
- * not part of the call, and not something an override should inherit
680
- * invisibly.
681
- */
682
- syncDiscovery: (http, ctx, snapshot) => requestJsonBody(
683
- http,
684
- `${catalogUrl(ctx)}/discovery/sync`,
685
- "Sync returned no body",
686
- { method: "POST", body: { snapshot } }
687
- )
688
- },
689
- { projectScoped: true }
690
- );
597
+ var catalogResource = defineResource("catalog", {
598
+ capabilities: async (http, ctx) => await requestJson(http, `${catalogUrl(ctx)}/capabilities`) ?? [],
599
+ features: async (http, ctx) => await requestJson(http, `${catalogUrl(ctx)}/features`) ?? [],
600
+ quotas: async (http, ctx) => await requestJson(http, `${catalogUrl(ctx)}/quotas`) ?? [],
601
+ reviewFeature: (http, ctx, featureKey, data) => requestJsonBody(
602
+ http,
603
+ `${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}/review`,
604
+ "Review returned no body",
605
+ { method: "PATCH", body: data }
606
+ ),
607
+ reviewQuota: (http, ctx, quotaKey, data) => requestJsonBody(
608
+ http,
609
+ `${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}/review`,
610
+ "Review returned no body",
611
+ { method: "PATCH", body: data }
612
+ ),
613
+ /** The translations are wrapped in `{ i18n }` here, not by the caller. */
614
+ setFeatureI18n: (http, ctx, featureKey, i18n) => requestJsonBody(
615
+ http,
616
+ `${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}/i18n`,
617
+ "i18n returned no body",
618
+ { method: "PATCH", body: { i18n } }
619
+ ),
620
+ setQuotaI18n: (http, ctx, quotaKey, i18n) => requestJsonBody(
621
+ http,
622
+ `${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}/i18n`,
623
+ "i18n returned no body",
624
+ { method: "PATCH", body: { i18n } }
625
+ ),
626
+ setFeatureBase: (http, ctx, featureKey, data) => requestJsonBody(
627
+ http,
628
+ `${catalogUrl(ctx)}/features/${encodeURIComponent(featureKey)}`,
629
+ "Base returned no body",
630
+ { method: "PATCH", body: data }
631
+ ),
632
+ setQuotaBase: (http, ctx, quotaKey, data) => requestJsonBody(
633
+ http,
634
+ `${catalogUrl(ctx)}/quotas/${encodeURIComponent(quotaKey)}`,
635
+ "Base returned no body",
636
+ { method: "PATCH", body: data }
637
+ ),
638
+ /**
639
+ * Writes a discovery snapshot into the catalogue.
640
+ *
641
+ * The request only. `useCatalogEntries.syncDiscovery` reloads the three
642
+ * lists afterwards, which is that composable keeping its refs true —
643
+ * not part of the call, and not something an override should inherit
644
+ * invisibly.
645
+ */
646
+ syncDiscovery: (http, ctx, snapshot) => requestJsonBody(
647
+ http,
648
+ `${catalogUrl(ctx)}/discovery/sync`,
649
+ "Sync returned no body",
650
+ { method: "POST", body: { snapshot } }
651
+ )
652
+ });
691
653
 
692
654
  // src/client/resources/dashboard.resource.ts
693
655
  function readValue(body) {
@@ -797,61 +759,57 @@ function projectionsUrl(ctx) {
797
759
  function settingsUrl(ctx) {
798
760
  return `${ctx.apiBase}/catalog/marketing-settings`;
799
761
  }
800
- var marketingResource = defineResource(
801
- "marketing",
802
- {
803
- listProjections: async (http, ctx, filter = {}) => {
804
- const params = new URLSearchParams();
805
- params.set("projectKey", ctx.projectKey);
806
- if (filter.targetType) params.set("targetType", filter.targetType);
807
- if (filter.targetVersionId) params.set("targetVersionId", filter.targetVersionId);
808
- if (filter.locale) params.set("locale", filter.locale);
809
- return await requestJson(
810
- http,
811
- `${projectionsUrl(ctx)}?${params.toString()}`
812
- ) ?? [];
813
- },
814
- /**
815
- * The request only. `useMarketingProjections.create` reloads the list
816
- * afterwards because a unique-tuple insert can change what the filter
817
- * matches — that is the composable keeping its refs true, not part of
818
- * the call.
819
- */
820
- createProjection: (http, ctx, data) => requestJsonBody(
821
- http,
822
- projectionsUrl(ctx),
823
- "Create returned no body",
824
- { method: "POST", body: data }
825
- ),
826
- updateProjection: (http, ctx, id, data) => requestJsonBody(
827
- http,
828
- `${projectionsUrl(ctx)}/${id}`,
829
- "Update returned no body",
830
- { method: "PATCH", body: data }
831
- ),
832
- deleteProjection: async (http, ctx, id) => {
833
- await requestJson(http, `${projectionsUrl(ctx)}/${id}`, { method: "DELETE" });
834
- },
835
- /**
836
- * The activated locale subset, or `null` when none was ever stored.
837
- *
838
- * `null` means the full pool is active — the server's answer for "no
839
- * row", and the state the page falls back to.
840
- */
841
- settings: (http, ctx) => requestJson(
762
+ function withQuery(url, params) {
763
+ const query = params.toString();
764
+ return query ? `${url}?${query}` : url;
765
+ }
766
+ var marketingResource = defineResource("marketing", {
767
+ listProjections: async (http, ctx, filter = {}) => {
768
+ const params = new URLSearchParams();
769
+ if (filter.targetType) params.set("targetType", filter.targetType);
770
+ if (filter.targetVersionId) params.set("targetVersionId", filter.targetVersionId);
771
+ if (filter.locale) params.set("locale", filter.locale);
772
+ return await requestJson(
842
773
  http,
843
- `${settingsUrl(ctx)}?projectKey=${encodeURIComponent(ctx.projectKey)}`
844
- ),
845
- /** `PUT`, not `PATCH`: the endpoint replaces the set it is given. */
846
- saveSettings: async (http, ctx, activeLocales) => {
847
- await requestJson(http, settingsUrl(ctx), {
848
- method: "PUT",
849
- body: { projectKey: ctx.projectKey, activeLocales }
850
- });
851
- }
774
+ withQuery(projectionsUrl(ctx), params)
775
+ ) ?? [];
852
776
  },
853
- { projectScoped: true }
854
- );
777
+ /**
778
+ * The request only. `useMarketingProjections.create` reloads the list
779
+ * afterwards because a unique-tuple insert can change what the filter
780
+ * matches — that is the composable keeping its refs true, not part of
781
+ * the call.
782
+ */
783
+ createProjection: (http, ctx, data) => requestJsonBody(
784
+ http,
785
+ projectionsUrl(ctx),
786
+ "Create returned no body",
787
+ { method: "POST", body: data }
788
+ ),
789
+ updateProjection: (http, ctx, id, data) => requestJsonBody(
790
+ http,
791
+ `${projectionsUrl(ctx)}/${id}`,
792
+ "Update returned no body",
793
+ { method: "PATCH", body: data }
794
+ ),
795
+ deleteProjection: async (http, ctx, id) => {
796
+ await requestJson(http, `${projectionsUrl(ctx)}/${id}`, { method: "DELETE" });
797
+ },
798
+ /**
799
+ * The activated locale subset, or `null` when none was ever stored.
800
+ *
801
+ * `null` means the full pool is active — the server's answer for "no
802
+ * row", and the state the page falls back to.
803
+ */
804
+ settings: (http, ctx) => requestJson(http, settingsUrl(ctx)),
805
+ /** `PUT`, not `PATCH`: the endpoint replaces the set it is given. */
806
+ saveSettings: async (http, ctx, activeLocales) => {
807
+ await requestJson(http, settingsUrl(ctx), {
808
+ method: "PUT",
809
+ body: { activeLocales }
810
+ });
811
+ }
812
+ });
855
813
 
856
814
  // src/client/resources/promo-codes.resource.ts
857
815
  function promoCodesUrl(ctx) {
@@ -902,29 +860,22 @@ var promoCodesResource = defineResource("promoCodes", {
902
860
  function promotionsUrl(ctx) {
903
861
  return `${ctx.apiBase}/catalog/promotions`;
904
862
  }
905
- var promotionsResource = defineResource(
906
- "promotions",
907
- {
908
- list: async (http, ctx) => await requestJson(
909
- http,
910
- `${promotionsUrl(ctx)}?projectKey=${encodeURIComponent(ctx.projectKey)}`
911
- ) ?? [],
912
- create: (http, ctx, data) => requestJsonBody(http, promotionsUrl(ctx), "Create returned no body", {
913
- method: "POST",
914
- body: data
915
- }),
916
- update: (http, ctx, id, data) => requestJsonBody(
917
- http,
918
- `${promotionsUrl(ctx)}/${id}`,
919
- "Update returned no body",
920
- { method: "PATCH", body: data }
921
- ),
922
- remove: async (http, ctx, id) => {
923
- await requestJson(http, `${promotionsUrl(ctx)}/${id}`, { method: "DELETE" });
924
- }
925
- },
926
- { projectScoped: true }
927
- );
863
+ var promotionsResource = defineResource("promotions", {
864
+ list: async (http, ctx) => await requestJson(http, promotionsUrl(ctx)) ?? [],
865
+ create: (http, ctx, data) => requestJsonBody(http, promotionsUrl(ctx), "Create returned no body", {
866
+ method: "POST",
867
+ body: data
868
+ }),
869
+ update: (http, ctx, id, data) => requestJsonBody(
870
+ http,
871
+ `${promotionsUrl(ctx)}/${id}`,
872
+ "Update returned no body",
873
+ { method: "PATCH", body: data }
874
+ ),
875
+ remove: async (http, ctx, id) => {
876
+ await requestJson(http, `${promotionsUrl(ctx)}/${id}`, { method: "DELETE" });
877
+ }
878
+ });
928
879
 
929
880
  // src/client/resources/tenants.resource.ts
930
881
  function tenantsUrl(ctx) {
@@ -938,16 +889,21 @@ var tenantsResource = defineResource("tenants", {
938
889
  detail: async (http, ctx, slug) => requestJson(http, tenantUrl(ctx, slug)),
939
890
  /**
940
891
  * Suspends a tenant. The reason is recorded on the audit trail, so it is a
941
- * required argument rather than an option with a default.
892
+ * required argument rather than an option with a default. Suspending and
893
+ * reactivating both require the second factor.
942
894
  */
943
- suspend: async (http, ctx, slug, reason) => {
895
+ suspend: async (http, ctx, slug, reason, mfaCode) => {
944
896
  await requestJson(http, `${tenantUrl(ctx, slug)}/suspend`, {
945
897
  method: "POST",
946
- body: { reason }
898
+ body: { reason },
899
+ headers: mfaHeader(mfaCode)
947
900
  });
948
901
  },
949
- reactivate: async (http, ctx, slug) => {
950
- await requestJson(http, `${tenantUrl(ctx, slug)}/reactivate`, { method: "POST" });
902
+ reactivate: async (http, ctx, slug, mfaCode) => {
903
+ await requestJson(http, `${tenantUrl(ctx, slug)}/reactivate`, {
904
+ method: "POST",
905
+ headers: mfaHeader(mfaCode)
906
+ });
951
907
  }
952
908
  });
953
909
 
@@ -982,7 +938,7 @@ var usersResource = defineResource("users", {
982
938
  {
983
939
  method: "POST",
984
940
  body: { reason },
985
- headers: mfaCode ? { "X-Mfa-Code": mfaCode } : void 0
941
+ headers: mfaHeader(mfaCode)
986
942
  }
987
943
  ),
988
944
  /** Same contract as `resetPassword`: app-served, audit-logged, MFA-gated. */
@@ -990,7 +946,7 @@ var usersResource = defineResource("users", {
990
946
  await requestJson(http, `${usersUrl(ctx)}/${encodeURIComponent(id)}/deactivate`, {
991
947
  method: "POST",
992
948
  body: { reason },
993
- headers: mfaCode ? { "X-Mfa-Code": mfaCode } : void 0
949
+ headers: mfaHeader(mfaCode)
994
950
  });
995
951
  }
996
952
  });
@@ -1052,9 +1008,6 @@ var pilotsResource = defineResource("pilots", {
1052
1008
  });
1053
1009
  }
1054
1010
  });
1055
- function mfaHeader(mfaCode) {
1056
- return mfaCode ? { "X-Mfa-Code": mfaCode } : void 0;
1057
- }
1058
1011
 
1059
1012
  // src/client/resources/platform-email.resource.ts
1060
1013
  function providersUrl(base) {
@@ -1069,18 +1022,18 @@ var platformEmailResource = defineResource("platformEmail", {
1069
1022
  http,
1070
1023
  providersUrl(ctx.apiBase),
1071
1024
  "Create returned no body",
1072
- { method: "POST", body: payload, headers: mfaHeader2(mfaCode) }
1025
+ { method: "POST", body: payload, headers: mfaHeader(mfaCode) }
1073
1026
  ),
1074
1027
  update: (http, ctx, id, payload, mfaCode) => requestJsonBody(
1075
1028
  http,
1076
1029
  `${providersUrl(ctx.apiBase)}/${encodeURIComponent(id)}`,
1077
1030
  "Update returned no body",
1078
- { method: "PATCH", body: payload, headers: mfaHeader2(mfaCode) }
1031
+ { method: "PATCH", body: payload, headers: mfaHeader(mfaCode) }
1079
1032
  ),
1080
1033
  remove: async (http, ctx, id, mfaCode) => {
1081
1034
  await requestJson(http, `${providersUrl(ctx.apiBase)}/${encodeURIComponent(id)}`, {
1082
1035
  method: "DELETE",
1083
- headers: mfaHeader2(mfaCode)
1036
+ headers: mfaHeader(mfaCode)
1084
1037
  });
1085
1038
  },
1086
1039
  /** Sends one mail through the provider and reports what happened. */
@@ -1111,7 +1064,7 @@ var emailHistoryResource = defineResource("emailHistory", {
1111
1064
  remove: async (http, ctx, id, mfaCode) => {
1112
1065
  await requestJson(http, `${historyUrl(ctx.apiBase)}/${encodeURIComponent(id)}`, {
1113
1066
  method: "DELETE",
1114
- headers: mfaHeader2(mfaCode)
1067
+ headers: mfaHeader(mfaCode)
1115
1068
  });
1116
1069
  },
1117
1070
  /**
@@ -1124,12 +1077,30 @@ var emailHistoryResource = defineResource("emailHistory", {
1124
1077
  resend: async (http, ctx, id, mfaCode) => requestJson(
1125
1078
  http,
1126
1079
  `${historyUrl(ctx.apiBase)}/${encodeURIComponent(id)}/resend`,
1127
- { method: "POST", headers: mfaHeader2(mfaCode) }
1080
+ { method: "POST", headers: mfaHeader(mfaCode) }
1128
1081
  )
1129
1082
  });
1130
- function mfaHeader2(mfaCode) {
1131
- return mfaCode ? { "X-Mfa-Code": mfaCode } : void 0;
1083
+
1084
+ // src/client/resources/settings.resource.ts
1085
+ function settingsUrl2(ctx) {
1086
+ return `${ctx.apiBase}/settings`;
1132
1087
  }
1088
+ var settingsResource = defineResource("settings", {
1089
+ read: async (http, ctx) => {
1090
+ const view = await requestJson(http, settingsUrl2(ctx));
1091
+ if (!view) throw new Error("GET /settings answered with no body");
1092
+ return view;
1093
+ },
1094
+ acknowledgeChange: async (http, ctx, id) => {
1095
+ const view = await requestJson(
1096
+ http,
1097
+ `${settingsUrl2(ctx)}/changes/${encodeURIComponent(id)}/acknowledge`,
1098
+ { method: "POST" }
1099
+ );
1100
+ if (!view) throw new Error("POST /settings/changes/{id}/acknowledge answered with no body");
1101
+ return view;
1102
+ }
1103
+ });
1133
1104
 
1134
1105
  // src/client/resources/index.ts
1135
1106
  var platformResources = {
@@ -1147,6 +1118,7 @@ var platformResources = {
1147
1118
  users: usersResource,
1148
1119
  subscriptions: subscriptionsResource,
1149
1120
  audit: auditResource,
1121
+ settings: settingsResource,
1150
1122
  // ── App-served, platform-shaped ──────────────────────────────────────────
1151
1123
  //
1152
1124
  // The platform ships pages for these three and serves no route for any of
@@ -1436,8 +1408,10 @@ var bundlesMessages = defineMessages(
1436
1408
  emptyBefore: "Noch keine Bundles angelegt. \xDCber",
1437
1409
  emptyAfter: "einen Bundle-Stamm anlegen, dann Features & Quotas in einer Draft-Version kuratieren.",
1438
1410
  strictWarnings: "{count} Strict-Mode-Warnung(en) bei letzter Operation",
1439
- confirmSoftDelete: "Bundle '{bundleKey}' wirklich soft-deleten? Bestand bleibt durch published BundleVersions gesch\xFCtzt.",
1440
- confirmDiscardVersion: "Diese Draft-Version verwerfen? Der Inhalt geht verloren."
1411
+ confirmSoftDeleteTitle: "Bundle soft-l\xF6schen?",
1412
+ confirmSoftDelete: "Bundle \u201E{label}\u201C soft-l\xF6schen? Alle {versions} Version(en) verschwinden aus der Verwaltung. Bereits verkaufte Best\xE4nde bleiben durch die published BundleVersions gesch\xFCtzt.",
1413
+ confirmDiscardVersionTitle: "Draft-Version verwerfen?",
1414
+ confirmDiscardVersion: "Diese Draft-Version verwerfen? Der bearbeitete Inhalt geht verloren und l\xE4sst sich nicht wiederherstellen."
1441
1415
  },
1442
1416
  header: {
1443
1417
  title: "Bundles",
@@ -1501,6 +1475,7 @@ var bundlesMessages = defineMessages(
1501
1475
  save: "Stammdaten & \xDCbersetzungen speichern",
1502
1476
  noVersion: "Noch keine Version. Lege eine neue Version an, um Features, Quotas & Pricing zu kuratieren.",
1503
1477
  publishVersion: "Diese Version publishen",
1478
+ unsavedChanges: "Ungespeicherte \xC4nderungen",
1504
1479
  softDelete: "Bundle soft-deleten"
1505
1480
  },
1506
1481
  // BundleCreatePanel — inline wizard for a new bundle (root + v1 draft).
@@ -1577,6 +1552,7 @@ var bundlesMessages = defineMessages(
1577
1552
  changeNotePlaceholder: "z. B. Add WhatsApp + Preisanpassung +4 \u20AC",
1578
1553
  selectedCount: "{count} ausgew\xE4hlt",
1579
1554
  saveTooltip: "\xC4nderungen speichern",
1555
+ saveVersion: "Version speichern",
1580
1556
  saveDisabledTooltip: "Form ist invalide oder unver\xE4ndert"
1581
1557
  },
1582
1558
  // BundlePlanCompatPicker — plans this bundle may be booked with.
@@ -1622,7 +1598,8 @@ var bundlesMessages = defineMessages(
1622
1598
  regressionBodySuffix: "-Confirm.",
1623
1599
  forceRegressive: "Trotzdem publishen",
1624
1600
  confirm: "Publishen",
1625
- confirmRegressive: "Regressiv publishen"
1601
+ confirmRegressive: "Regressiv publishen",
1602
+ mfaDescription: "Version v{version} von Bundle {bundleKey} publishen."
1626
1603
  }
1627
1604
  },
1628
1605
  {
@@ -1650,8 +1627,10 @@ var bundlesMessages = defineMessages(
1650
1627
  emptyBefore: "No bundles created yet. Use",
1651
1628
  emptyAfter: "to create a bundle master record, then curate features & quotas in a draft version.",
1652
1629
  strictWarnings: "{count} strict mode warning(s) in the last operation",
1653
- confirmSoftDelete: "Really soft-delete bundle '{bundleKey}'? Existing contracts stay protected by published bundle versions.",
1654
- confirmDiscardVersion: "Discard this draft version? Its content will be lost."
1630
+ confirmSoftDeleteTitle: "Soft-delete bundle?",
1631
+ confirmSoftDelete: 'Soft-delete bundle "{label}"? All {versions} version(s) leave the administration. Contracts already sold stay protected by the published bundle versions.',
1632
+ confirmDiscardVersionTitle: "Discard draft version?",
1633
+ confirmDiscardVersion: "Discard this draft version? The edited content is lost and cannot be restored."
1655
1634
  },
1656
1635
  header: {
1657
1636
  title: "Bundles",
@@ -1713,6 +1692,7 @@ var bundlesMessages = defineMessages(
1713
1692
  save: "Save master data & translations",
1714
1693
  noVersion: "No version yet. Create a new version to curate features, quotas & pricing.",
1715
1694
  publishVersion: "Publish this version",
1695
+ unsavedChanges: "Unsaved changes",
1716
1696
  softDelete: "Soft-delete bundle"
1717
1697
  },
1718
1698
  create: {
@@ -1783,6 +1763,7 @@ var bundlesMessages = defineMessages(
1783
1763
  changeNotePlaceholder: "e.g. Add WhatsApp + price adjustment +4 \u20AC",
1784
1764
  selectedCount: "{count} selected",
1785
1765
  saveTooltip: "Save changes",
1766
+ saveVersion: "Save version",
1786
1767
  saveDisabledTooltip: "Form is invalid or unchanged"
1787
1768
  },
1788
1769
  featuresEditor: {
@@ -1826,7 +1807,8 @@ var bundlesMessages = defineMessages(
1826
1807
  regressionBodySuffix: " confirmation.",
1827
1808
  forceRegressive: "Publish anyway",
1828
1809
  confirm: "Publish",
1829
- confirmRegressive: "Publish regressively"
1810
+ confirmRegressive: "Publish regressively",
1811
+ mfaDescription: "Publish version v{version} of bundle {bundleKey}."
1830
1812
  }
1831
1813
  }
1832
1814
  );
@@ -2033,14 +2015,18 @@ var discoveryMessages = defineMessages(
2033
2015
  noQuotasDeclared: "Keine Quotas im Code deklariert.",
2034
2016
  orphansTitle: "Capabilities ohne Feature",
2035
2017
  noOwner: "Ohne Owner",
2036
- owner: "Owner",
2018
+ owner: "Besitzer",
2037
2019
  unit: "Einheit",
2038
2020
  replacedBy: "ersetzt durch {key}",
2039
2021
  replaces: "ersetzt: {keys}",
2040
2022
  reapproveEmphasis: "erneut freigeben",
2041
2023
  capList: {
2042
2024
  orphanFeature: "Feature im Katalog ohne implementierende Capability \u2014 blockiert im blocking-Strict-Mode das Plan-Publish.",
2043
- removedFromCode: "aus Code entfernt"
2025
+ flagNew: "neu",
2026
+ flagExperimental: "experimentell",
2027
+ flagDeprecated: "veraltet",
2028
+ removedFromCode: "aus Code entfernt",
2029
+ implementedAt: "implementiert in"
2044
2030
  },
2045
2031
  kpi: {
2046
2032
  featuresTotal: "Features gesamt",
@@ -2100,14 +2086,6 @@ var discoveryMessages = defineMessages(
2100
2086
  noUsageProviderWarning: "Eine harte Quota ohne UsageProvider ist nicht deploy-f\xE4hig (Preflight).",
2101
2087
  outdatedBanner: "Die code-abgeleiteten Quota-Fakten (Einheit/Enforcement/Provider) haben sich seit der letzten Freigabe ge\xE4ndert \u2014 bitte pr\xFCfen und"
2102
2088
  },
2103
- caps: {
2104
- emptyHint: "Feature im Katalog ohne implementierende Capability \u2014 blockiert im blocking-Strict-Mode das Plan-Publish.",
2105
- flagNew: "neu",
2106
- flagExperimental: "experimental",
2107
- flagDeprecated: "deprecated",
2108
- flagRemoved: "aus Code entfernt",
2109
- implementedAt: "impl"
2110
- },
2111
2089
  trans: {
2112
2090
  sourceBadge: "Source",
2113
2091
  fieldLabel: "Label",
@@ -2141,7 +2119,11 @@ var discoveryMessages = defineMessages(
2141
2119
  reapproveEmphasis: "approve again",
2142
2120
  capList: {
2143
2121
  orphanFeature: "Feature in the catalog without an implementing capability \u2014 blocks plan publishing in blocking strict mode.",
2144
- removedFromCode: "removed from code"
2122
+ flagNew: "new",
2123
+ flagExperimental: "experimental",
2124
+ flagDeprecated: "deprecated",
2125
+ removedFromCode: "removed from code",
2126
+ implementedAt: "implemented at"
2145
2127
  },
2146
2128
  kpi: {
2147
2129
  featuresTotal: "Features total",
@@ -2201,14 +2183,6 @@ var discoveryMessages = defineMessages(
2201
2183
  noUsageProviderWarning: "A hard quota without a UsageProvider is not deployable (preflight).",
2202
2184
  outdatedBanner: "The code-derived quota facts (unit/enforcement/provider) have changed since the last approval \u2014 please review and"
2203
2185
  },
2204
- caps: {
2205
- emptyHint: "Feature in the catalog without an implementing capability \u2014 blocks the plan publish in blocking strict mode.",
2206
- flagNew: "new",
2207
- flagExperimental: "experimental",
2208
- flagDeprecated: "deprecated",
2209
- flagRemoved: "removed from code",
2210
- implementedAt: "impl"
2211
- },
2212
2186
  trans: {
2213
2187
  sourceBadge: "Source",
2214
2188
  fieldLabel: "Label",
@@ -2420,8 +2394,10 @@ var marketingMessages = defineMessages(
2420
2394
  colPlan: "Plan",
2421
2395
  colVisible: "Sichtbar",
2422
2396
  colBadge: "Badge",
2423
- colPriority: "Priorit\xE4t",
2397
+ colOrder: "Reihenfolge",
2424
2398
  colHighlight: "Highlight",
2399
+ reorderLabel: "{plan} verschieben \xB7 Position {position} von {total}",
2400
+ reorderTitle: "Ziehen oder Pfeiltasten: Reihenfolge \xE4ndern",
2425
2401
  versionTabsLabel: "Plan-Versionen f\xFCr {plan}",
2426
2402
  versionTitle: "Version {version}: g\xFCltig {from} bis {until}{changeNote}",
2427
2403
  versionValidFromUnknown: "unbekannt",
@@ -2544,8 +2520,10 @@ var marketingMessages = defineMessages(
2544
2520
  colPlan: "Plan",
2545
2521
  colVisible: "Visible",
2546
2522
  colBadge: "Badge",
2547
- colPriority: "Priority",
2523
+ colOrder: "Order",
2548
2524
  colHighlight: "Highlight",
2525
+ reorderLabel: "Move {plan} \xB7 position {position} of {total}",
2526
+ reorderTitle: "Drag or use the arrow keys to reorder",
2549
2527
  versionTabsLabel: "Plan versions for {plan}",
2550
2528
  versionTitle: "Version {version}: valid {from} to {until}{changeNote}",
2551
2529
  versionValidFromUnknown: "unknown",
@@ -2641,7 +2619,8 @@ var navMessages = defineMessages(
2641
2619
  bundles: "Bundles",
2642
2620
  marketingCatalog: "Marketing-Catalog",
2643
2621
  platformEmail: "Plattform-E-Mail",
2644
- platformEmailHistory: "E-Mail-Verlauf"
2622
+ platformEmailHistory: "E-Mail-Verlauf",
2623
+ settings: "Einstellungen"
2645
2624
  },
2646
2625
  sections: {
2647
2626
  overview: "\xDCbersicht",
@@ -2664,7 +2643,8 @@ var navMessages = defineMessages(
2664
2643
  bundles: "Bundles",
2665
2644
  marketingCatalog: "Marketing catalog",
2666
2645
  platformEmail: "Platform email",
2667
- platformEmailHistory: "Email history"
2646
+ platformEmailHistory: "Email history",
2647
+ settings: "Settings"
2668
2648
  },
2669
2649
  sections: {
2670
2650
  overview: "Overview",
@@ -3325,8 +3305,7 @@ var planVersionsMessages = defineMessages(
3325
3305
  diffFields: {
3326
3306
  featuresAdded: "Hinzugef\xFCgte Features",
3327
3307
  featuresRemoved: "Entfernte Features",
3328
- maxUsers: "Max. Benutzer",
3329
- maxStorageGb: "Speicher (GB)",
3308
+ quota: 'Kontingent \u201E{key}"',
3330
3309
  monthlyNet: "Preis monatlich (netto)",
3331
3310
  yearlyNet: "Preis j\xE4hrlich (netto)",
3332
3311
  unitSize: "Einheitsgr\xF6\xDFe"
@@ -3377,8 +3356,7 @@ var planVersionsMessages = defineMessages(
3377
3356
  diffFields: {
3378
3357
  featuresAdded: "Added features",
3379
3358
  featuresRemoved: "Removed features",
3380
- maxUsers: "Max. users",
3381
- maxStorageGb: "Storage (GB)",
3359
+ quota: 'Quota "{key}"',
3382
3360
  monthlyNet: "Price monthly (net)",
3383
3361
  yearlyNet: "Price yearly (net)",
3384
3362
  unitSize: "Unit size"
@@ -3413,6 +3391,9 @@ var plansMessages = defineMessages(
3413
3391
  toastPlanDeleted: "Plan {planKey} komplett aus der DB gel\xF6scht.",
3414
3392
  toastDraftDiscarded: "Draft v{version} von {planKey} verworfen \u2014 Live-Version unver\xE4ndert.",
3415
3393
  toastVersionTerminated: "v{version} terminiert.",
3394
+ mfaPublish: "v{version} von {planKey} ver\xF6ffentlichen.",
3395
+ mfaTerminate: "Live-Version v{version} von {planKey} beenden.",
3396
+ mfaPurge: "Plan {planKey} endg\xFCltig l\xF6schen.",
3416
3397
  errorSessionExpiredSave: "Sitzung abgelaufen \u2014 bitte neu anmelden und erneut speichern.",
3417
3398
  errorStrictMode: "Strict-Mode-Check: {details}",
3418
3399
  errorStrictModeFallback: "Drift gegen den Discovery-Snapshot.",
@@ -3444,8 +3425,7 @@ var plansMessages = defineMessages(
3444
3425
  yearlyNet: "Preis (j\xE4hrlich, netto)",
3445
3426
  featuresRemoved: "Entfernte Features",
3446
3427
  featuresAdded: "Hinzugef\xFCgte Features",
3447
- quotasLowered: "Gesenkte Quotas",
3448
- quotasRaised: "Erh\xF6hte Quotas",
3428
+ quota: 'Kontingent \u201E{key}"',
3449
3429
  bundlesRemoved: "Entfernte Bundles",
3450
3430
  bundlesAdded: "Hinzugef\xFCgte Bundles"
3451
3431
  },
@@ -3645,6 +3625,9 @@ var plansMessages = defineMessages(
3645
3625
  toastPlanDeleted: "Plan {planKey} completely removed from the database.",
3646
3626
  toastDraftDiscarded: "Draft v{version} of {planKey} discarded \u2014 live version unchanged.",
3647
3627
  toastVersionTerminated: "v{version} terminated.",
3628
+ mfaPublish: "Publish v{version} of {planKey}.",
3629
+ mfaTerminate: "End live version v{version} of {planKey}.",
3630
+ mfaPurge: "Delete plan {planKey} for good.",
3648
3631
  errorSessionExpiredSave: "Session expired \u2014 please sign in again and save once more.",
3649
3632
  errorStrictMode: "Strict mode check: {details}",
3650
3633
  errorStrictModeFallback: "Drift against the discovery snapshot.",
@@ -3675,8 +3658,7 @@ var plansMessages = defineMessages(
3675
3658
  yearlyNet: "Price (yearly, net)",
3676
3659
  featuresRemoved: "Removed features",
3677
3660
  featuresAdded: "Added features",
3678
- quotasLowered: "Lowered quotas",
3679
- quotasRaised: "Raised quotas",
3661
+ quota: 'Quota "{key}"',
3680
3662
  bundlesRemoved: "Removed bundles",
3681
3663
  bundlesAdded: "Added bundles"
3682
3664
  },
@@ -3873,6 +3855,7 @@ var promosMessages = defineMessages(
3873
3855
  columnCode: "Code",
3874
3856
  columnValue: "Wert",
3875
3857
  columnRedemptions: "Einl\xF6sungen",
3858
+ redemptionsHeld: "{redeemed} + {held} reserviert / {max}",
3876
3859
  columnCampaign: "Kampagne",
3877
3860
  columnValidUntil: "G\xFCltig bis",
3878
3861
  actionPause: "Pausieren",
@@ -3970,6 +3953,7 @@ var promosMessages = defineMessages(
3970
3953
  columnCode: "Code",
3971
3954
  columnValue: "Value",
3972
3955
  columnRedemptions: "Redemptions",
3956
+ redemptionsHeld: "{redeemed} + {held} held / {max}",
3973
3957
  columnCampaign: "Campaign",
3974
3958
  columnValidUntil: "Valid until",
3975
3959
  actionPause: "Pause",
@@ -4057,6 +4041,74 @@ var promosMessages = defineMessages(
4057
4041
  }
4058
4042
  );
4059
4043
 
4044
+ // src/client/i18n/messages/settings.ts
4045
+ var settingsMessages = defineMessages(
4046
+ {
4047
+ title: "Einstellungen",
4048
+ subtitle: "Was diese Installation ausf\xFChrt \u2014 und seit wann.",
4049
+ applied: {
4050
+ title: "Angewendete Konfiguration",
4051
+ appliedAt: "Angewendet am",
4052
+ source: "Quelle",
4053
+ fingerprint: "Fingerabdruck",
4054
+ notRecorded: "Diese Installation zeichnet nicht auf, wann ihre Konfiguration angewendet wurde: der Persistenz-Adapter liefert keinen `core.appliedSettings`-Port. Die Werte unten sind die laufenden.",
4055
+ recordStale: "Der Datensatz beschreibt eine fr\xFChere Konfiguration \u2014 der Start konnte ihn nicht schreiben. Die Werte unten sind die laufenden; siehe das Boot-Log.",
4056
+ readOnly: "Nur lesen. Diese Werte leben in der Datei; eine \xC4nderung dort greift beim n\xE4chsten Start."
4057
+ },
4058
+ changes: {
4059
+ title: "\xC4nderungen zwischen zwei Starts",
4060
+ empty: "Kein Start hat die Einstellungen ver\xE4ndert vorgefunden.",
4061
+ noticedAt: "Bemerkt am",
4062
+ leaf: "Einstellung",
4063
+ before: "Vorher",
4064
+ after: "Nachher",
4065
+ absent: "\u2014 nicht gesetzt \u2014",
4066
+ acknowledge: "Als gesehen markieren",
4067
+ acknowledgedBy: "Gesehen von {who} am {when}",
4068
+ open: "Ungesehen",
4069
+ acknowledged: "Gesehen"
4070
+ },
4071
+ values: {
4072
+ title: "Laufende Werte",
4073
+ value: "Wert"
4074
+ },
4075
+ loadFailed: "Die Einstellungen konnten nicht geladen werden.",
4076
+ acknowledgeFailed: "Die \xC4nderung konnte nicht als gesehen markiert werden."
4077
+ },
4078
+ {
4079
+ title: "Settings",
4080
+ subtitle: "What this installation is running on \u2014 and since when.",
4081
+ applied: {
4082
+ title: "Applied configuration",
4083
+ appliedAt: "Applied at",
4084
+ source: "Source",
4085
+ fingerprint: "Fingerprint",
4086
+ notRecorded: "This installation does not record when its configuration was applied: the persistence adapter provides no `core.appliedSettings` port. The values below are the running ones.",
4087
+ recordStale: "The record describes an earlier configuration \u2014 the start could not write it. The values below are the running ones; see the boot log.",
4088
+ readOnly: "Read-only. These values live in the file; a change there takes effect at the next start."
4089
+ },
4090
+ changes: {
4091
+ title: "Changes between two starts",
4092
+ empty: "No start has found the settings changed.",
4093
+ noticedAt: "Noticed at",
4094
+ leaf: "Setting",
4095
+ before: "Before",
4096
+ after: "After",
4097
+ absent: "\u2014 not set \u2014",
4098
+ acknowledge: "Mark as seen",
4099
+ acknowledgedBy: "Seen by {who} on {when}",
4100
+ open: "Unseen",
4101
+ acknowledged: "Seen"
4102
+ },
4103
+ values: {
4104
+ title: "Running values",
4105
+ value: "Value"
4106
+ },
4107
+ loadFailed: "The settings could not be loaded.",
4108
+ acknowledgeFailed: "The change could not be marked as seen."
4109
+ }
4110
+ );
4111
+
4060
4112
  // src/client/i18n/messages/shell.ts
4061
4113
  var shellMessages = defineMessages(
4062
4114
  {
@@ -4409,7 +4461,8 @@ function catalogFor(locale) {
4409
4461
  marketing: marketingMessages[locale],
4410
4462
  promos: promosMessages[locale],
4411
4463
  pilots: pilotsMessages[locale],
4412
- email: emailMessages[locale]
4464
+ email: emailMessages[locale],
4465
+ settings: settingsMessages[locale]
4413
4466
  };
4414
4467
  }
4415
4468
  var SA_MESSAGES = {
@@ -4453,6 +4506,7 @@ function createSaCatalog(options = {}) {
4453
4506
  }
4454
4507
 
4455
4508
  export {
4509
+ attachCause,
4456
4510
  formatMessage,
4457
4511
  markPlatformError,
4458
4512
  isPlatformError,
@@ -4473,6 +4527,7 @@ export {
4473
4527
  trimTrailingSlashes,
4474
4528
  getJson,
4475
4529
  postJson,
4530
+ patchJson,
4476
4531
  createFetchHttpClient,
4477
4532
  defaultKvStore,
4478
4533
  defaultHttpClient,
@@ -4491,6 +4546,8 @@ export {
4491
4546
  clampListPage,
4492
4547
  clampListPageSize,
4493
4548
  defineListOp,
4549
+ MFA_CODE_HEADER,
4550
+ mfaHeader,
4494
4551
  plansResource,
4495
4552
  planVersionsResource,
4496
4553
  bundlesResource,
@@ -4508,6 +4565,7 @@ export {
4508
4565
  pilotsResource,
4509
4566
  platformEmailResource,
4510
4567
  emailHistoryResource,
4568
+ settingsResource,
4511
4569
  platformResources,
4512
4570
  BootLoadError,
4513
4571
  BootLoader,