@saasicat/ui-vue 0.27.0 → 1.0.0-rc.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 (242) hide show
  1. package/README.md +8 -8
  2. package/dist/.build-stamp +1 -0
  3. package/dist/batch-column-fetcher-BlRPjUST.d.cts +482 -0
  4. package/dist/batch-column-fetcher-zs-5eqB9.d.ts +482 -0
  5. package/dist/{catalog-Dv2twuNi.d.cts → catalog-Q7RPiOHD.d.cts} +238 -9
  6. package/dist/{catalog-Dv2twuNi.d.ts → catalog-Q7RPiOHD.d.ts} +238 -9
  7. package/dist/{chunk-NRVF3JJJ.js → chunk-5GVZKTJY.js} +3 -306
  8. package/dist/chunk-7TDWP76O.js +304 -0
  9. package/dist/chunk-LEWVBULC.js +2752 -0
  10. package/dist/{chunk-LK6YJDXC.js → chunk-RSRDRTVZ.js} +60 -20
  11. package/dist/{chunk-4IZWT4UY.js → chunk-SOB6CK3R.js} +219 -12
  12. package/dist/client/index.cjs +224 -16
  13. package/dist/client/index.d.cts +50 -477
  14. package/dist/client/index.d.ts +50 -477
  15. package/dist/client/index.js +24 -12
  16. package/dist/index.cjs +314 -443
  17. package/dist/index.d.cts +10 -1930
  18. package/dist/index.d.ts +10 -1930
  19. package/dist/index.js +96 -3036
  20. package/dist/quasar/index.cjs +264 -22
  21. package/dist/quasar/index.d.cts +2 -2
  22. package/dist/quasar/index.d.ts +2 -2
  23. package/dist/quasar/index.js +2 -2
  24. package/dist/{resource-registry-Cn1Gy2LE.d.ts → resource-registry-BQlRV_Fi.d.cts} +14 -3
  25. package/dist/{resource-registry-BxFpnzHY.d.cts → resource-registry-DFWs4x5p.d.ts} +14 -3
  26. package/dist/{testing-e2e → testing}/admin-pages-suite.cjs +1 -1
  27. package/dist/{testing-e2e → testing}/admin-pages-suite.js +1 -1
  28. package/dist/vue/index.cjs +7823 -0
  29. package/dist/vue/index.d.cts +1594 -0
  30. package/dist/vue/index.d.ts +1594 -0
  31. package/dist/vue/index.js +190 -0
  32. package/package.json +26 -15
  33. package/src/{pages-standard → auth}/SuperAdminLoginPage.vue +5 -13
  34. package/src/{pages-standard → auth}/SuperAdminSetupWizard.vue +5 -13
  35. package/src/client/admin-error.ts +24 -5
  36. package/src/client/batch-column-fetcher.ts +0 -10
  37. package/src/client/i18n/locale.ts +13 -1
  38. package/src/client/manifest-loader.ts +0 -11
  39. package/src/client/resources/audit.resource.ts +47 -15
  40. package/src/client/resources/dashboard.resource.ts +64 -0
  41. package/src/{pages-standard → client/resources}/email-history.types.ts +6 -5
  42. package/src/client/resources/index.ts +48 -23
  43. package/src/client/resources/pilots.resource.ts +101 -0
  44. package/src/client/resources/pilots.types.ts +56 -0
  45. package/src/client/resources/platform-email.resource.ts +163 -0
  46. package/src/{pages-standard → client/resources}/platform-email.types.ts +6 -4
  47. package/src/client/resources/promo-codes.resource.ts +25 -0
  48. package/src/client/resources/users.resource.ts +35 -0
  49. package/src/{components/bundle-editor → features/bundle}/BundleVersionInlineEditor.vue +10 -6
  50. package/src/{components → features/bundle}/BundleVersionPublishDialog.vue +98 -126
  51. package/src/{components/bundle-editor → features/bundle}/BundleVersionStrip.vue +1 -1
  52. package/src/{components → features/bundle}/VersionDiffPreview.vue +2 -2
  53. package/src/{components/bundle-editor → features/bundle/internal}/BundleCreatePanel.vue +2 -2
  54. package/src/{components/bundle-editor → features/bundle/internal}/BundleFeaturesEditor.vue +1 -1
  55. package/src/{components/bundle-editor → features/bundle/internal}/BundlePlanCompatPicker.vue +1 -1
  56. package/src/{components/bundle-editor → features/bundle/internal}/BundleQuotasEditor.vue +1 -1
  57. package/src/{components/bundle-editor → features/bundle/internal}/BundleStatusBanner.vue +2 -2
  58. package/src/{components/bundle-editor → features/bundle/internal}/bundle-version-status.ts +6 -2
  59. package/src/{components → features/marketing}/MarketingPromotionsTab.vue +4 -4
  60. package/src/{components/plan-create-dialog → features/plan}/PlanCreateDialog.vue +55 -139
  61. package/src/{components/plan-detail → features/plan}/PlanDetail.vue +6 -6
  62. package/src/{components/plan-matrix → features/plan}/PlanMatrix.vue +2 -2
  63. package/src/{components/plan-review → features/plan}/PlanReview.vue +2 -2
  64. package/src/features/plan/PlanTerminateDialog.vue +88 -0
  65. package/src/{components/plan-version-editor → features/plan}/PlanVersionEditor.vue +9 -9
  66. package/src/{components/plan-detail → features/plan/internal}/PlanAuditLog.vue +4 -4
  67. package/src/{components/plan-version-editor → features/plan/internal}/PlanCatalogPreview.vue +3 -3
  68. package/src/{components/plan-version-editor → features/plan/internal}/PlanComponentPool.vue +3 -3
  69. package/src/{components/plan-detail → features/plan/internal}/PlanDetailKpis.vue +4 -4
  70. package/src/{components/plan-detail → features/plan/internal}/PlanTitleEdit.vue +1 -1
  71. package/src/{components/plan-version-editor → features/plan/internal}/PlanVersionBasket.vue +3 -3
  72. package/src/features/plan/internal/PlanVersionDiffDialog.vue +69 -0
  73. package/src/{components/plan-detail → features/plan/internal}/PlanVersionDiffPanel.vue +4 -4
  74. package/src/{components/plan-version-editor → features/plan/internal}/PlanVersionEditorHeader.vue +3 -3
  75. package/src/{components/plan-detail → features/plan/internal}/PlanVersionsPanel.vue +4 -4
  76. package/src/features/plan/plan-area-context.ts +121 -0
  77. package/src/{components → features/tenant}/TenantActionConfirmDialog.vue +70 -77
  78. package/src/index.ts +6 -6
  79. package/src/{pages-standard → internal}/bundles-page/BundleAccordionList.vue +2 -2
  80. package/src/{pages-standard → internal}/bundles-page/BundleDetailPanel.vue +4 -4
  81. package/src/{pages-standard → internal}/bundles-page/BundlesKpis.vue +2 -2
  82. package/src/{pages-standard → internal}/bundles-page/BundlesToolbar.vue +1 -1
  83. package/src/{pages-standard → internal}/bundles-page/types.ts +1 -1
  84. package/src/internal/dialogs/PilotCreateDialog.vue +578 -0
  85. package/src/{components → internal}/dialogs/PilotEditDialog.vue +114 -147
  86. package/src/internal/dialogs/PromoCodeCreateDialog.vue +129 -0
  87. package/src/{components → internal}/dialogs/PromoCodeDialogFields.vue +28 -18
  88. package/src/{components → internal}/dialogs/PromoCodeEditDialog.vue +64 -158
  89. package/src/{components → internal}/dialogs/types.ts +8 -32
  90. package/src/{pages-standard → internal}/discovery-page/DiscoveryFeatureCard.vue +1 -1
  91. package/src/{pages-standard → internal}/discovery-page/DiscoveryKpis.vue +2 -2
  92. package/src/{pages-standard → internal}/discovery-page/DiscoveryQuotaCard.vue +1 -1
  93. package/src/internal/email-history/email-history.types.ts +14 -0
  94. package/src/{pages-standard → internal}/marketing-catalog/MarketingCatalogHeader.vue +1 -1
  95. package/src/{pages-standard → internal}/plan-versions/PlanDiffCard.vue +1 -1
  96. package/src/{pages-standard → internal}/plans-page/PlanArchiveDialog.vue +20 -21
  97. package/src/{pages-standard → internal}/plans-page/PlanBundleOverview.vue +1 -1
  98. package/src/{pages-standard → internal}/plans-page/PlanDiscardDraftDialog.vue +15 -16
  99. package/src/internal/plans-page/PlanPublishDialog.vue +118 -0
  100. package/src/internal/platform-email/platform-email.types.ts +11 -0
  101. package/src/{pages-standard → internal}/tenant-detail/TenantMasterData.vue +1 -1
  102. package/src/{pages-standard → internal}/tenant-detail/TenantUsage.vue +1 -1
  103. package/src/{pages-standard → internal}/tenant-detail/TenantUsers.vue +1 -1
  104. package/src/{pages-standard → layouts}/AdminLayout.vue +44 -7
  105. package/src/{pages-standard → pages}/AdminManifestErrorPage.vue +17 -2
  106. package/src/{pages-standard → pages}/AuditPage.vue +45 -38
  107. package/src/{pages-standard → pages}/BundlesPage.vue +233 -159
  108. package/src/{pages-standard → pages}/DashboardPage.vue +84 -127
  109. package/src/{pages-standard → pages}/DiscoveryPage.vue +164 -77
  110. package/src/{pages-standard → pages}/EmailHistoryPage.vue +149 -154
  111. package/src/{pages-standard → pages}/MarketingCatalogPage.vue +64 -61
  112. package/src/{pages-standard → pages}/PilotsPage.vue +143 -144
  113. package/src/pages/PlanReviewPage.vue +127 -0
  114. package/src/pages/PlanVersionEditorPage.vue +85 -0
  115. package/src/{pages-standard → pages}/PlansPage.vue +176 -253
  116. package/src/{pages-standard → pages}/PlatformEmailPage.vue +141 -148
  117. package/src/{pages-standard → pages}/PromoCodeDetailPage.vue +82 -67
  118. package/src/{pages-standard → pages}/PromoCodesPage.vue +103 -75
  119. package/src/{pages-standard → pages}/SubscriptionsPage.vue +21 -10
  120. package/src/{pages-standard → pages}/TenantDetailPage.vue +116 -64
  121. package/src/{pages-standard → pages}/TenantsPage.vue +135 -135
  122. package/src/{pages-standard → pages}/UsersPage.vue +122 -86
  123. package/src/pages/index.ts +155 -0
  124. package/src/quasar/confirm.ts +1 -1
  125. package/src/quasar/create-super-admin-app.ts +3 -4
  126. package/src/{testing-e2e → testing}/admin-pages-suite.ts +1 -1
  127. package/src/ui/data/AdminRowActions.vue +49 -0
  128. package/src/ui/data/AdminStatusPill.vue +31 -0
  129. package/src/{components → ui/entitlement}/FeatureGate.vue +1 -1
  130. package/src/ui/feedback/AdminBanner.vue +71 -0
  131. package/src/ui/feedback/AdminEmptyState.vue +30 -0
  132. package/src/ui/feedback/AdminErrorBanner.vue +41 -0
  133. package/src/ui/overlay/AdminConfirmDialog.vue +133 -0
  134. package/src/ui/overlay/AdminDialog.vue +60 -0
  135. package/src/ui/overlay/AdminFormDialog.vue +104 -0
  136. package/src/{components → ui/overlay}/MfaPromptDialog.vue +1 -1
  137. package/src/ui/page/AdminField.vue +56 -0
  138. package/src/ui/page/AdminFieldGrid.vue +11 -0
  139. package/src/ui/page/AdminToolbar.vue +27 -0
  140. package/src/{components → ui/page}/LocaleSwitcher.vue +2 -2
  141. package/src/{components → ui/page}/ThemeSwitcher.vue +2 -2
  142. package/src/ui/theme/components/banner.css +116 -0
  143. package/src/ui/theme/components/dialog.css +101 -0
  144. package/src/ui/theme/components/toolbar.css +199 -0
  145. package/src/ui/theme/index.css +3 -0
  146. package/src/ui/theme/tokens.scale.css +3 -0
  147. package/src/ui/theme/tokens.semantic.dark.css +1 -1
  148. package/src/vue/create-admin-routes.ts +4 -8
  149. package/src/vue/entitlement-provider.ts +1 -1
  150. package/src/vue/index.ts +57 -0
  151. package/src/vue/plan-wizard.ts +107 -0
  152. package/src/vue/platform-loaders.ts +0 -3
  153. package/src/vue/resource-registry.ts +95 -10
  154. package/src/vue/status.ts +44 -0
  155. package/src/vue/super-admin-context.ts +8 -8
  156. package/src/vue/ui-confirm.ts +1 -1
  157. package/src/vue/ui-notify.ts +1 -1
  158. package/src/vue/use-api-list.ts +0 -3
  159. package/src/vue/use-audit-entries.ts +0 -2
  160. package/src/vue/use-bulk-publish.ts +0 -3
  161. package/src/vue/use-bundle-versions-map.ts +1 -3
  162. package/src/vue/use-bundles.ts +2 -6
  163. package/src/vue/use-catalog-entries.ts +1 -3
  164. package/src/vue/use-discovery.ts +0 -10
  165. package/src/vue/use-entitlement.ts +2 -5
  166. package/src/vue/use-live-plan-versions.ts +2 -4
  167. package/src/vue/use-manifest.ts +1 -1
  168. package/src/vue/use-marketing-projections.ts +1 -3
  169. package/src/vue/use-plans.ts +2 -6
  170. package/src/vue/use-promotions.ts +1 -3
  171. package/src/vue/use-resource-list.ts +17 -7
  172. package/src/vue/use-sa-theme.ts +1 -1
  173. package/src/vue/use-super-admin-i18n.ts +1 -1
  174. package/src/vue/use-tenant-billing-catalog.ts +1 -1
  175. package/src/vue/use-tenant-billing.ts +0 -3
  176. package/src/vue/use-tenant-manifest.ts +0 -3
  177. package/src/vue/use-tenant-subscription-bundles.ts +1 -3
  178. package/src/vue/use-tenants.ts +0 -2
  179. package/src/components/dialogs/PilotCreateDialog.vue +0 -603
  180. package/src/components/dialogs/PromoCodeCreateDialog.vue +0 -222
  181. package/src/components/plan/PlanCycleToggle.vue +0 -103
  182. package/src/components/plan/PlanGrid.vue +0 -207
  183. package/src/components/plan/PriceSummary.vue +0 -293
  184. package/src/components/plan/PromoCodeInput.vue +0 -192
  185. package/src/components/plan/PublicBundleGrid.vue +0 -291
  186. package/src/components/plan-detail/PlanTerminateDialog.vue +0 -89
  187. package/src/components/plan-version-editor/PlanVersionDiffDialog.vue +0 -85
  188. package/src/pages-standard/plans-page/PlanPublishDialog.vue +0 -117
  189. package/src/pages-standard/tenants/StatusPill.vue +0 -62
  190. package/src/pages-tenant/LimitsRow.vue +0 -67
  191. package/src/pages-tenant/MySubscriptionBundlesPage.vue +0 -648
  192. package/src/pages-tenant/OnboardingConfigurator.vue +0 -413
  193. package/src/pages-tenant/PackageSnapshotPanel.vue +0 -264
  194. package/src/pages-tenant/PendingVersionBanner.vue +0 -126
  195. package/src/pages-tenant/PlanChangeWizard.vue +0 -580
  196. package/src/pages-tenant/TenantPlanSection.vue +0 -675
  197. package/src/pages-tenant/UsageBar.vue +0 -107
  198. package/src/pages-tenant/default-i18n.ts +0 -609
  199. package/src/pages-tenant/tenant-plan-section/BundlePreviewDialog.vue +0 -306
  200. package/src/pages-tenant/tenant-plan-section/TenantBundleStore.vue +0 -322
  201. package/src/pages-tenant/tenant-plan-section/TenantFeatureMatrix.vue +0 -125
  202. package/src/pages-tenant/tenant-plan-section/TenantPlanCardHeader.vue +0 -67
  203. package/src/pages-tenant/tenant-plan-section/TenantUsageGrid.vue +0 -31
  204. /package/dist/{testing-e2e → testing}/admin-pages-suite.d.cts +0 -0
  205. /package/dist/{testing-e2e → testing}/admin-pages-suite.d.ts +0 -0
  206. /package/src/{components/bundle-editor → features/bundle/internal}/catalog-i18n.ts +0 -0
  207. /package/src/{components/plan-list → features/plan}/PlanList.vue +0 -0
  208. /package/src/{components/plan-detail/types.ts → features/plan/internal/plan-detail.types.ts} +0 -0
  209. /package/src/{components/plan-version-editor/types.ts → features/plan/internal/plan-version-editor.types.ts} +0 -0
  210. /package/src/{pages-standard → internal}/bundles-page/BundlesFilterBar.vue +0 -0
  211. /package/src/{components → internal}/dialogs/pilot-dialog.css +0 -0
  212. /package/src/{pages-standard → internal}/discovery-page/CatalogEntryTransPanel.vue +0 -0
  213. /package/src/{pages-standard → internal}/discovery-page/DiscoveryCapList.vue +0 -0
  214. /package/src/{pages-standard → internal}/discovery-page/DiscoveryMetaBanner.vue +0 -0
  215. /package/src/{pages-standard → internal}/discovery-page/DiscoveryStatusControl.vue +0 -0
  216. /package/src/{pages-standard → internal}/discovery-page/discovery-ui.ts +0 -0
  217. /package/src/{pages-standard → internal}/marketing-catalog/MarketingCatalogAdmin.vue +0 -0
  218. /package/src/{pages-standard → internal}/marketing-catalog/MarketingCatalogPreview.vue +0 -0
  219. /package/src/{pages-standard → internal}/marketing-catalog/MarketingCatalogToolbar.vue +0 -0
  220. /package/src/{pages-standard → internal}/marketing-catalog/types.ts +0 -0
  221. /package/src/{pages-standard → internal}/plan-versions/PlanVersionsDiff.vue +0 -0
  222. /package/src/{pages-standard → internal}/plan-versions/PlanVersionsTimeline.vue +0 -0
  223. /package/src/{pages-standard → internal}/plan-versions/catalog-history.types.ts +0 -0
  224. /package/src/{pages-standard → internal}/plan-versions/format.ts +0 -0
  225. /package/src/{pages-standard → internal}/plans-page/PlansPageToast.vue +0 -0
  226. /package/src/{pages-standard → internal}/plans-page/types.ts +0 -0
  227. /package/src/{pages-standard → internal}/tenant-detail/types.ts +0 -0
  228. /package/src/{pages-standard → internal}/tenants/format.ts +0 -0
  229. /package/src/{components/admin-page → ui/data}/AdminKpi.vue +0 -0
  230. /package/src/{components/admin-page → ui/data}/AdminPaginator.vue +0 -0
  231. /package/src/{components/admin-page → ui/data}/AdminStatistics.vue +0 -0
  232. /package/src/{components/admin-page → ui/data}/AdminTable.vue +0 -0
  233. /package/src/{components → ui/data}/KvBlock.vue +0 -0
  234. /package/src/{components/admin-page → ui/feedback}/AdminRefreshBtn.vue +0 -0
  235. /package/src/{components/admin-page → ui/page}/AdminAccordion.vue +0 -0
  236. /package/src/{components/admin-page → ui/page}/AdminBody.vue +0 -0
  237. /package/src/{components/admin-page → ui/page}/AdminFilters.vue +0 -0
  238. /package/src/{components/admin-page → ui/page}/AdminHero.vue +0 -0
  239. /package/src/{components/admin-page → ui/page}/AdminPage.vue +0 -0
  240. /package/src/{components/admin-page → ui/page}/AdminSection.vue +0 -0
  241. /package/src/{components/wizard-stepper → ui/page}/WizardStepper.vue +0 -0
  242. /package/src/{pages-standard → ui/theme}/sa-theme.css +0 -0
package/README.md CHANGED
@@ -15,12 +15,12 @@ The package is layered so that each entry only loads what it names.
15
15
  Lower layers never import upward; ESLint (`no-restricted-imports`, repo
16
16
  root config) enforces the boundaries in CI.
17
17
 
18
- | Entry | Source | May import | Contents |
19
- | ----------------------------------------------------------------------- | -------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
20
- | `@saasicat/ui-vue/client` | `src/client/` | `@saasicat/types` only | Framework-free core: `BootLoader`, `ManifestLoader` (ETag cache), nav builder, action registry, batch column fetcher, the `HttpClient`/`KvStore` contract with its `fetch` and axios adapters, `AdminError`. Usable from any framework or plain Node/TypeScript. |
21
- | `@saasicat/ui-vue` (main) | `src/vue/` (+ client re-exports) | Vue, `vue-router`, Pinia — **no Quasar** | Composables (`useTenants`, `usePlanEditor`, …), router guards, injection keys + shell contract, notify-port type, optional Pinia store factory. |
22
- | `@saasicat/ui-vue/quasar` | `src/quasar/` | everything above + Quasar | `createSuperAdminApp()` bootstrap and the Quasar notify-port implementation. |
23
- | `@saasicat/ui-vue/pages-standard/*`, `/pages-tenant/*`, `/components/*` | SFC directories | everything | The Quasar reference UI, shipped as raw `.vue` from `src/` (compiled by the consumer's Vite). |
18
+ | Entry | Source | May import | Contents |
19
+ | ----------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
20
+ | `@saasicat/ui-vue/client` | `src/client/` | `@saasicat/types` only | Framework-free core: `BootLoader`, `ManifestLoader` (ETag cache), nav builder, action registry, batch column fetcher, the `HttpClient`/`KvStore` contract with its `fetch` and axios adapters, `AdminError`. Usable from any framework or plain Node/TypeScript. |
21
+ | `@saasicat/ui-vue` (main) | `src/vue/` (+ client re-exports) | Vue, `vue-router`, Pinia — **no Quasar** | Composables (`useTenants`, `usePlanEditor`, …), router guards, injection keys + shell contract, notify-port type, optional Pinia store factory. |
22
+ | `@saasicat/ui-vue/quasar` | `src/quasar/` | everything above + Quasar | `createSuperAdminApp()` bootstrap and the Quasar notify-port implementation. |
23
+ | `@saasicat/ui-vue/pages/*.vue`, `/layouts/*.vue`, `/auth/*.vue`, `/ui/*.vue`, `/pages-tenant/*` | SFC directories | everything | The Quasar reference UI, shipped as raw `.vue` from `src/` (compiled by the consumer's Vite). |
24
24
 
25
25
  ### The shipped source has a language floor
26
26
 
@@ -52,8 +52,8 @@ Rules of thumb when contributing:
52
52
  - Quasar imports in `.ts` files are only allowed under `src/quasar/`.
53
53
  - A few framework-free type/i18n modules stay co-located with their SFCs
54
54
  (`components/dialogs/types.ts`, `components/bundle-editor/catalog-i18n.ts`,
55
- `pages-standard/platform-email.types.ts`,
56
- `pages-standard/email-history.types.ts`, `pages-tenant/default-i18n.ts`)
55
+ `internal/platform-email/platform-email.types.ts`,
56
+ `internal/email-history/email-history.types.ts`, `pages-tenant/default-i18n.ts`)
57
57
  and are whitelisted in the ESLint rules — they must not grow framework
58
58
  imports.
59
59
 
@@ -0,0 +1 @@
1
+ c0ad4bfbe61ec2533f28d5a963436a4c73dd8f8c82d3c138e9138b98cc34d5a8
@@ -0,0 +1,482 @@
1
+ import { a5 as SaMessages, H as HttpClient, l as KvStore, a2 as SaLocale, aA as SaNavMessages } from './catalog-Q7RPiOHD.cjs';
2
+ import { PublicBootResponse, AdminManifest, StandardPageKey, TenantColumnDef } from '@saasicat/types';
3
+
4
+ /**
5
+ * Marks an error as one this package raised. Called by the package's own error
6
+ * classes in their constructors; nothing else should call it.
7
+ */
8
+ declare function markPlatformError(error: Error): void;
9
+ /** Whether an error came from this package, across bundle copies. */
10
+ declare function isPlatformError(value: unknown): boolean;
11
+ /**
12
+ * Marks an error as the empty-body sentinel: the call reached the server, the
13
+ * server answered, and the body the caller needed was not in it. Returns the
14
+ * error so a throw site stays one expression.
15
+ *
16
+ * Called at those throw sites only — never in a constructor, because the class
17
+ * is also raised for calls that failed outright.
18
+ */
19
+ declare function markEmptyResponse<E extends Error>(error: E): E;
20
+ /** Whether an error is that sentinel, across bundle copies. */
21
+ declare function isEmptyResponse(value: unknown): boolean;
22
+ /**
23
+ * Marks an error as one the request did not survive: no connection, DNS
24
+ * failure, CORS rejection, abort, or a client that reported the same by
25
+ * resolving without an HTTP status. Returns the error so a throw site stays one
26
+ * expression.
27
+ */
28
+ declare function markTransportFailure<E>(error: E): E;
29
+ /** Whether an error is a declared transport failure, across bundle copies. */
30
+ declare function isTransportFailure(value: unknown): boolean;
31
+ interface AdminErrorInit {
32
+ /** HTTP status. `0` means the request never produced one. */
33
+ status?: number;
34
+ /** Machine-readable code from the response body (`{ code }`). */
35
+ code?: string;
36
+ /** Parsed response body, when there was one. */
37
+ body?: unknown;
38
+ /** Requested URL, when known. */
39
+ url?: string;
40
+ /** Request method, when known. */
41
+ method?: string;
42
+ /**
43
+ * Text the failing side supplied. Never invent one — its absence is the
44
+ * signal that only a translated fallback can be shown.
45
+ */
46
+ detail?: string;
47
+ /**
48
+ * The request completed and the answer was unusable — a 2xx that carried
49
+ * no body where one was required.
50
+ *
51
+ * Its own state because the model could not otherwise tell it from a
52
+ * transport failure: both have no HTTP status to report, and both were
53
+ * therefore `status: 0`. They need opposite words. A request that never
54
+ * left says "check your connection"; one the server accepted and answered
55
+ * with nothing says "check whether the change was applied", because it may
56
+ * well have been.
57
+ */
58
+ emptyResponse?: boolean;
59
+ /**
60
+ * The request never reached the server.
61
+ *
62
+ * Its own state for the same reason as `emptyResponse`: neither has an HTTP
63
+ * status to reason from, so a status of `0` cannot tell them apart — and
64
+ * neither can it tell either of them from an error that simply carries no
65
+ * status, such as a bug in page code. Only the seam that made the request
66
+ * knows, and it says so with `markTransportFailure`.
67
+ */
68
+ transportFailure?: boolean;
69
+ /** Diagnostic message. Derived from the fields above when omitted. */
70
+ message?: string;
71
+ /** The error this one was built from. */
72
+ cause?: unknown;
73
+ }
74
+ /** A failed admin API call, in the one shape the package works with. */
75
+ declare class AdminError extends Error {
76
+ /** HTTP status. `0` means the request never produced one. */
77
+ readonly status: number;
78
+ /** Machine-readable code from the response body, when it carried one. */
79
+ readonly code?: string;
80
+ /** Parsed response body, when there was one. */
81
+ readonly body?: unknown;
82
+ /** Requested URL, when known. */
83
+ readonly url?: string;
84
+ /** Request method, when known. */
85
+ readonly method?: string;
86
+ /**
87
+ * Text the failing side supplied — the only candidate for user-facing
88
+ * output. `undefined` when nothing was supplied.
89
+ */
90
+ readonly detail?: string;
91
+ /** The request completed but the answer was unusable. See `AdminErrorInit`. */
92
+ readonly emptyResponse: boolean;
93
+ /** The request never reached the server. See `AdminErrorInit`. */
94
+ readonly transportFailure: boolean;
95
+ /**
96
+ * The error this one was raised from, when `AdminErrorInit` carried one.
97
+ *
98
+ * `declare` because the property is real but not emitted here: `attachCause`
99
+ * defines it, exactly as the ES2022 `Error` constructor would. The
100
+ * declaration is what makes it *readable* — `Error.cause` lives in
101
+ * `lib.es2022.error.d.ts`, and this package supports consumers on ES2021,
102
+ * where taking a cause in and never being able to read it out would be a
103
+ * one-way public API.
104
+ *
105
+ * Not `readonly`, unlike its siblings: the inherited `Error.cause` is
106
+ * writable, and narrowing that in a patch release would reject assignments
107
+ * a consumer can make today on ES2022.
108
+ */
109
+ cause?: unknown;
110
+ constructor(init?: AdminErrorInit);
111
+ }
112
+ /** Whether `err` is an `AdminError`, including one from another bundle copy. */
113
+ /**
114
+ * The HTTP status an error carries, whichever shape carries it.
115
+ *
116
+ * An `AdminError` has it at `status`; an axios rejection has it at
117
+ * `response.status`. The pages used to read only the second, which was right
118
+ * while they called axios themselves — since they ask the resource registry,
119
+ * every failure is an `AdminError`, and a 401 read as `undefined` turned the
120
+ * MFA prompt's "try the code again" into "close and start over".
121
+ */
122
+ declare function httpStatusOf(err: unknown): number | undefined;
123
+ declare function isAdminError(err: unknown): err is AdminError;
124
+ /**
125
+ * Whether an error is axios saying, in its own words, that the request was made
126
+ * and no response ever arrived.
127
+ *
128
+ * This is the one transport failure read rather than branded, because a library
129
+ * cannot be asked to mark itself. What it reads is axios's own three-way split,
130
+ * documented under "Handling errors" in its README and visible in the
131
+ * `AxiosError` constructor: `response` is set only when the server answered,
132
+ * `request` only once one was actually made, and an error with neither happened
133
+ * while the request was still being set up.
134
+ *
135
+ * Measured against axios 1.18.1 driven at a real `node:http` server, and the
136
+ * groups came out disjoint:
137
+ *
138
+ * | rejection | `isAxiosError` | `request` | `response` |
139
+ * | ----------------------------------------------- | -------------- | --------- | ---------- |
140
+ * | connection refused / reset, DNS, timeout, abort | `true` | yes | no |
141
+ * | the same, rethrown by a rejection interceptor | `true` | yes | no |
142
+ * | a 401 or 500 the server really sent | `true` | yes | yes |
143
+ * | interceptor rejects with `new Error(…)` | absent | no | no |
144
+ * | …the same, but copying `error.config` across | absent | no | no |
145
+ * | …the same, copying `config` and `request` | absent | yes | no |
146
+ * | unsupported protocol, signal aborted before call | `true` | no | no |
147
+ * | request interceptor throws, malformed URL | absent | no | no |
148
+ *
149
+ * Three readings follow from that table, and only the first is free of choice:
150
+ *
151
+ * - `response` present means the server answered, whatever else is set.
152
+ * - `request` present without it is axios's "made, nothing came back". The
153
+ * browser and `fetch` adapters attach it too — an `XMLHttpRequest` and a
154
+ * `Request` respectively — so the reading is not Node-only.
155
+ * - Requiring `isAxiosError` on top of that is the decision. It removes the
156
+ * ordinary interceptor that copies `config` and `request` onto a hand-built
157
+ * `new Error`, which is shape-wise axios's no-response form after the server
158
+ * had answered.
159
+ *
160
+ * The previous reading was `config` without `response`, which is not axios's
161
+ * statement about anything: `config` is echoed on every axios error including
162
+ * the ones carrying a 401, and it is the field an interceptor is most likely to
163
+ * carry over when it replaces the rejection. It matched three rows above that
164
+ * mean the opposite of a transport failure.
165
+ *
166
+ * ## What this cannot decide, and which way it errs
167
+ *
168
+ * This is read *after* the consumer's interceptors have run — after the one
169
+ * place that can set or delete any field on the rejection. Both readings are
170
+ * therefore forgeable, in both directions, and each was reproduced:
171
+ *
172
+ * - An interceptor that **drops** `request` — `AxiosError.from(err, code,
173
+ * config)` without its fourth argument, `err.toJSON()`, or a `delete
174
+ * err.request` before logging — leaves a genuine `ECONNREFUSED` unbranded.
175
+ * The operator then reads `connect ECONNREFUSED 127.0.0.1:44947` instead of
176
+ * the localized sentence.
177
+ * - An interceptor that **builds** one — `AxiosError.from(msg, code,
178
+ * error.config, error.request)` after an answered 401 — is branded. Nothing
179
+ * distinguishes it: `AxiosError.from` is public API, so `isAxiosError` is
180
+ * available to user code as well.
181
+ *
182
+ * Neither is closable by a better predicate; the fields simply do not carry the
183
+ * fact by then. So the reading errs deliberately toward *not* branding, because
184
+ * the two mistakes do not cost the same: an unbranded transport failure shows a
185
+ * true sentence in the wrong register, while a branded application failure tells
186
+ * the operator to check a connection that is fine. Saying less beats saying
187
+ * something false.
188
+ *
189
+ * An interceptor that rewrites rejections should say what it means with
190
+ * `markTransportFailure`, which is exported for exactly this. It is checked
191
+ * first and settles the case.
192
+ */
193
+ declare function isAxiosNoResponseError(value: unknown): boolean;
194
+ /**
195
+ * Reads the human-readable message out of a response body.
196
+ *
197
+ * Covers the two shapes the platform and its host produce: a coded platform
198
+ * error (`{ code, message }`) carries a string, while a NestJS
199
+ * `ValidationPipe` rejection carries `message: string[]` — one entry per
200
+ * failed constraint. Joining them is what keeps a validation error readable
201
+ * instead of rendering as `[object Object]`.
202
+ *
203
+ * Exported because every place that builds an `AdminError` from a response
204
+ * needs the same answer. It had two implementations for one release and they
205
+ * disagreed: the one in `http-json.ts` accepted only a string, so a validation
206
+ * rejection arriving through `getJson`/`postJson` lost its constraints
207
+ * entirely and the operator was shown the generic fallback.
208
+ */
209
+ declare function readErrorDetail(body: unknown): string | undefined;
210
+ /** Reads the machine-readable code out of a response body, if it carries one. */
211
+ declare function readErrorCode(body: unknown): string | undefined;
212
+ /**
213
+ * Turns anything that was caught into an `AdminError`.
214
+ *
215
+ * Recognises, in order: an `AdminError` (from any bundle copy), an axios-style
216
+ * rejection, an error carrying a numeric `status` — which is every one of the
217
+ * package's own `*ApiError` classes — and finally any `Error`, string or
218
+ * unknown value.
219
+ */
220
+ declare function toAdminError(err: unknown): AdminError;
221
+ /**
222
+ * Turns anything that was caught into text for a user.
223
+ *
224
+ * What the failing side said outranks anything this package could guess, so a
225
+ * `detail` wins whenever there is one. After that come the two facts a seam
226
+ * declared about a request with no HTTP status — they need opposite sentences
227
+ * and no number can tell them apart — and only then the status.
228
+ *
229
+ * The last line is the honest one. An error with no status, no text and no
230
+ * declaration is an error nothing knows anything about; "check your connection"
231
+ * used to be the answer, and it sent an operator after their router for a null
232
+ * dereference in a page. Whoever knows better says so with
233
+ * `markTransportFailure` or `markEmptyResponse`.
234
+ *
235
+ * `useAsyncAction` and `AdminErrorBanner` call this for you, and a page that
236
+ * reaches the platform through either should not need it. The five pages that
237
+ * do call it directly still notify from their own catch blocks; each had grown
238
+ * its own copy of this function, and one decision reached from five places
239
+ * beats five decisions.
240
+ */
241
+ declare function adminErrorMessage(err: unknown, msgs: SaMessages['errors']): string;
242
+
243
+ interface BootLoaderOptions {
244
+ /**
245
+ * Fully-qualified boot endpoint incl. app globalPrefix
246
+ * (`/api/admin/boot`, `/api/v1/admin/boot`, …). Mandatory.
247
+ */
248
+ endpoint: string;
249
+ /** Defaults to `defaultHttpClient()` (= `fetch`). */
250
+ http?: HttpClient;
251
+ }
252
+ declare class BootLoadError extends Error {
253
+ readonly status: number;
254
+ constructor(status: number, message: string);
255
+ }
256
+ declare class BootLoader {
257
+ private readonly endpoint;
258
+ private readonly http;
259
+ constructor(options: BootLoaderOptions);
260
+ load(): Promise<PublicBootResponse>;
261
+ }
262
+
263
+ interface ManifestLoaderOptions {
264
+ /**
265
+ * Fully-qualified manifest endpoint incl. app globalPrefix
266
+ * (`/api/admin/manifest`, `/api/v1/admin/manifest`, …). Mandatory.
267
+ */
268
+ endpoint: string;
269
+ http?: HttpClient;
270
+ storage?: KvStore;
271
+ /**
272
+ * Storage key prefix — consumers with multiple apps under one domain
273
+ * set this to e.g. `'ma:'` or `'da:'`, so that the caches
274
+ * are separated.
275
+ */
276
+ storageKeyPrefix?: string;
277
+ }
278
+ /**
279
+ * The manifest could not be loaded. Its `message` is a diagnostic for the log,
280
+ * never text for a screen — `markPlatformError` is what tells `toAdminError`
281
+ * so, and it is a promise this class has to keep at every throw site.
282
+ */
283
+ declare class ManifestLoadError extends Error {
284
+ readonly status: number;
285
+ constructor(status: number, message: string);
286
+ }
287
+ interface CachedManifestEntry {
288
+ etag: string;
289
+ body: AdminManifest;
290
+ }
291
+ declare class ManifestLoader {
292
+ private readonly endpoint;
293
+ private readonly http;
294
+ private readonly storage;
295
+ private readonly bodyKey;
296
+ private readonly etagKey;
297
+ constructor(options: ManifestLoaderOptions);
298
+ /**
299
+ * Loads the current manifest. On a cache hit (304) the cached
300
+ * body is returned — otherwise the fresh server body.
301
+ *
302
+ * A 304 with no usable cached body is not a failure to report but one to
303
+ * undo: the request only carried `If-None-Match` because this loader put
304
+ * the ETag there, and the cache it validated against is this loader's own.
305
+ * So it drops the pair and asks once more without the header, which is the
306
+ * same recovery a person would have had to trigger by hand — except that
307
+ * the person reading an admin screen has neither this loader nor a
308
+ * console. Exactly one retry: a 304 to a request that asked nothing
309
+ * conditional is a server fault, and no repetition fixes it.
310
+ */
311
+ load(): Promise<AdminManifest>;
312
+ /** Sends the manifest GET, conditional when an ETag is supplied. */
313
+ private request;
314
+ /** Takes a non-304 response as the current manifest and caches it. */
315
+ private acceptFresh;
316
+ /** Reads the cached manifest body from storage; null if absent. */
317
+ readCachedBody(): CachedManifestEntry | null;
318
+ /** Clears the cache — e.g. on logout or after `manifest reload`. */
319
+ clearCache(): void;
320
+ }
321
+
322
+ /**
323
+ * Default routes for the platform standard pages. Consumers may override this
324
+ * via the `standardPageRoutes` option (e.g. `/admin/users` →
325
+ * `/admin/team`).
326
+ */
327
+ declare const DEFAULT_STANDARD_PAGE_ROUTES: Record<StandardPageKey, string>;
328
+ interface BuildRouteEntry {
329
+ /** Stable identifier — the key for standard pages, the `id` for project pages. */
330
+ id: string;
331
+ /** Route path (`/admin/...`). */
332
+ path: string;
333
+ /** Visible for the UI. */
334
+ label: string;
335
+ icon?: string;
336
+ /** Sort key for drawer groups. */
337
+ navSection?: string;
338
+ /** Lookup key in the `extensions:` map (project) or the platform standard map. */
339
+ componentKey: string;
340
+ /** Required capability or null. */
341
+ requiredCapability: string | null;
342
+ /** Platform standard page (`true`) or project page (`false`). */
343
+ isStandard: boolean;
344
+ /** Hint for anticipatory lazy loading. */
345
+ prefetchOnIdle?: boolean;
346
+ }
347
+ interface NavBuilderOptions {
348
+ /**
349
+ * UI locale for the default labels and section names, default `'de'`.
350
+ * Pass the same locale to `buildSidebar()`'s `sectionOrder` (via
351
+ * `defaultSectionOrder(locale)`) — section names are compared as strings.
352
+ *
353
+ * Only resolves the two catalogs the platform ships. Prefer `nav`, which
354
+ * carries app overrides and app-supplied languages as well.
355
+ */
356
+ locale?: SaLocale;
357
+ /**
358
+ * Resolved `nav` namespace, as `useSuperAdminI18n().messages.value.nav`
359
+ * hands it out. Wins over `locale`, and is the only way the sidebar sees
360
+ * `i18n.overrides` or a language the app added itself.
361
+ */
362
+ nav?: SaNavMessages;
363
+ /**
364
+ * Optional: overrides the default routes for certain standard pages.
365
+ * Consumers set this if they want an alternative URL structure.
366
+ */
367
+ standardPageRoutes?: Partial<Record<StandardPageKey, string>>;
368
+ /**
369
+ * Per-page label overrides layered over the locale defaults.
370
+ */
371
+ standardPageLabels?: Partial<Record<StandardPageKey, string>>;
372
+ /** Default icons for standard pages. */
373
+ standardPageIcons?: Partial<Record<StandardPageKey, string>>;
374
+ /** Default `navSection` for standard pages. */
375
+ standardPageNavSection?: Partial<Record<StandardPageKey, string>>;
376
+ /**
377
+ * Optional: set of known `componentKey`s from the shell's `extensions:`
378
+ * map. ProjectPages whose `componentKey` is not contained here
379
+ * are filtered out — they would otherwise appear in the sidebar but on
380
+ * click be redirected by the catch-all (silent dead link).
381
+ * Consumers without an `extensions:` map omit the field → as before.
382
+ */
383
+ availableExtensions?: Set<string>;
384
+ }
385
+ /**
386
+ * Localized default section names in drawer order (Übersicht → Produktkatalog
387
+ * → Kunden → System). Pass the result to `buildSidebar()` when building routes
388
+ * with a non-default locale, or hand it the resolved `nav` catalog directly —
389
+ * section names are compared as strings, so both sides must come from the same
390
+ * source.
391
+ */
392
+ declare function defaultSectionOrder(locale?: SaLocale | SaNavMessages): readonly string[];
393
+ /**
394
+ * Returns the list of all routes defined by the current manifest —
395
+ * filtered to the capabilities that the logged-in user has.
396
+ *
397
+ * The consumer shell then builds its Vue router configuration and its
398
+ * sidebar drawer from it.
399
+ */
400
+ declare function buildRoutes(manifest: AdminManifest, options?: NavBuilderOptions): BuildRouteEntry[];
401
+ interface SidebarItem {
402
+ id: string;
403
+ path: string;
404
+ label: string;
405
+ icon?: string;
406
+ }
407
+ interface SidebarSection {
408
+ /** `null` for the default section (items without `navSection`). */
409
+ section: string | null;
410
+ items: SidebarItem[];
411
+ }
412
+ /**
413
+ * Groups the routes by `navSection` for the drawer.
414
+ *
415
+ * Section order:
416
+ * 1. Default section (`null`) — items without `navSection`.
417
+ * 2. Sections from `sectionOrder` in exactly this order.
418
+ * 3. Remaining sections alphabetically.
419
+ *
420
+ * The default order matches the plan simulation layout (Übersicht →
421
+ * Produktkatalog → Kunden → System); consumers can override it.
422
+ */
423
+ declare function buildSidebar(routes: BuildRouteEntry[], sectionOrder?: readonly string[]): SidebarSection[];
424
+ /**
425
+ * Returns the Vue component registered for the given `componentKey`.
426
+ * The consumer shell calls this function with its own `extensions:` map.
427
+ * For unknown keys → `null` (the UI then renders a fallback
428
+ * component, e.g. "Component not found in shell build").
429
+ *
430
+ * `extensions` is `Record<string, T>` — `T` is typically a
431
+ * Vue component (either imported directly or as a
432
+ * `defineAsyncComponent` wrapper).
433
+ */
434
+ declare function resolveExtension<T>(componentKey: string, extensions: Record<string, T>): T | null;
435
+
436
+ type BatchColumnValue = unknown;
437
+ /** One value per `tenantId` (freely structured). */
438
+ type BatchColumnRow = Record<string, BatchColumnValue>;
439
+ /** One `tenantId → value` map per column key. */
440
+ type BatchColumnData = Record<string, BatchColumnRow>;
441
+ type ParamStyle = 'comma' | 'repeat';
442
+ interface BatchColumnFetcherOptions {
443
+ http?: HttpClient;
444
+ /**
445
+ * How the `tenantIds` are passed to the endpoint. Default `'comma'` →
446
+ * `?tenantIds=t1,t2,t3`. `'repeat'` → `?tenantIds=t1&tenantIds=t2`.
447
+ * Consumer backends decide based on their framework (NestJS accepts
448
+ * comma-separated strings by default, or via `@Query() ids: string[]`).
449
+ */
450
+ paramStyle?: ParamStyle;
451
+ }
452
+ declare class BatchColumnDriftError extends Error {
453
+ readonly column: TenantColumnDef;
454
+ constructor(column: TenantColumnDef, reason: string);
455
+ }
456
+ declare class BatchColumnFetcher {
457
+ private readonly http;
458
+ private readonly paramStyle;
459
+ constructor(options?: BatchColumnFetcherOptions);
460
+ /**
461
+ * Loads the data for all columns declared in the manifest in parallel
462
+ * (one request per column, all `tenantIds` in the batch). Columns without
463
+ * a satisfied capability are ignored.
464
+ */
465
+ fetchAll(manifest: AdminManifest, tenantIds: string[]): Promise<BatchColumnData>;
466
+ /** Fetch a single column (consumers may also use this directly). */
467
+ fetchOne(column: TenantColumnDef, tenantIds: string[]): Promise<BatchColumnRow>;
468
+ /**
469
+ * Column drift against the manifest. Consumers use this for CI smoke
470
+ * tests of the manifest-vs-shell build.
471
+ */
472
+ listDriftIssues(manifest: AdminManifest): BatchColumnDriftError[];
473
+ /**
474
+ * Which columns have a satisfied `requiredCapability`? Manifest =
475
+ * discovery, so a local check is enough.
476
+ */
477
+ eligibleColumns(manifest: AdminManifest): TenantColumnDef[];
478
+ private validateBatchEndpoint;
479
+ private buildUrl;
480
+ }
481
+
482
+ export { AdminError as A, type BatchColumnData as B, type CachedManifestEntry as C, DEFAULT_STANDARD_PAGE_ROUTES as D, readErrorCode as E, readErrorDetail as F, resolveExtension as G, toAdminError as H, ManifestLoadError as M, type NavBuilderOptions as N, type ParamStyle as P, type SidebarItem as S, type AdminErrorInit as a, BatchColumnDriftError as b, BatchColumnFetcher as c, type BatchColumnFetcherOptions as d, type BatchColumnRow as e, type BatchColumnValue as f, BootLoadError as g, BootLoader as h, type BootLoaderOptions as i, type BuildRouteEntry as j, ManifestLoader as k, type ManifestLoaderOptions as l, type SidebarSection as m, adminErrorMessage as n, buildRoutes as o, buildSidebar as p, defaultSectionOrder as q, httpStatusOf as r, isAdminError as s, isAxiosNoResponseError as t, isEmptyResponse as u, isPlatformError as v, isTransportFailure as w, markEmptyResponse as x, markPlatformError as y, markTransportFailure as z };