@saasicat/ui-vue 0.7.0 → 0.9.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 (41) hide show
  1. package/dist/{chunk-A3W2N26K.js → chunk-66BUSVC5.js} +68 -217
  2. package/dist/{chunk-X5SQ5HMB.js → chunk-TBLXKSTR.js} +0 -137
  3. package/dist/{chunk-QZOSDCNP.js → chunk-TY2WYKME.js} +1 -1
  4. package/dist/client/index.cjs +180 -463
  5. package/dist/client/index.d.cts +32 -57
  6. package/dist/client/index.d.ts +32 -57
  7. package/dist/client/index.js +4 -6
  8. package/dist/index.cjs +273 -580
  9. package/dist/index.d.cts +10 -55
  10. package/dist/index.d.ts +10 -55
  11. package/dist/index.js +76 -101
  12. package/dist/{messages-7b0P8W75.d.ts → messages-BIYw32u1.d.cts} +0 -67
  13. package/dist/{messages-7b0P8W75.d.cts → messages-BIYw32u1.d.ts} +0 -67
  14. package/dist/quasar/index.cjs +0 -136
  15. package/dist/quasar/index.d.cts +2 -2
  16. package/dist/quasar/index.d.ts +2 -2
  17. package/dist/quasar/index.js +2 -2
  18. package/dist/{use-super-admin-i18n-B3v3-SWZ.d.ts → use-super-admin-i18n-CWNu_W3u.d.ts} +1 -1
  19. package/dist/{use-super-admin-i18n-DMktRVEt.d.cts → use-super-admin-i18n-DL_qI1BY.d.cts} +1 -1
  20. package/package.json +5 -5
  21. package/src/client/admin-resource-client.ts +112 -0
  22. package/src/client/i18n/messages/nav.ts +0 -2
  23. package/src/client/i18n/messages/plan-versions.ts +0 -143
  24. package/src/client/index.ts +1 -2
  25. package/src/client/nav-builder.ts +9 -4
  26. package/src/index.ts +0 -1
  27. package/src/pages-standard/AdminLayout.vue +1 -1
  28. package/src/pages-standard/plan-versions/PlanVersionsDiff.vue +1 -1
  29. package/src/pages-standard/plan-versions/PlanVersionsTimeline.vue +1 -1
  30. package/src/pages-standard/plan-versions/catalog-history.types.ts +37 -0
  31. package/src/pages-standard/plan-versions/format.ts +2 -38
  32. package/src/client/plan-versions-catalog.ts +0 -380
  33. package/src/pages-standard/PlanVersionsPage.vue +0 -220
  34. package/src/pages-standard/plan-versions/PlanVersionHeader.vue +0 -309
  35. package/src/pages-standard/plan-versions/PlanVersionStatusBadge.vue +0 -48
  36. package/src/pages-standard/plan-versions/PlanVersionsAudit.vue +0 -326
  37. package/src/pages-standard/plan-versions/PlanVersionsKpi.vue +0 -65
  38. package/src/pages-standard/plan-versions/PlanVersionsList.vue +0 -315
  39. package/src/pages-standard/plan-versions/PlanVersionsMatrix.vue +0 -261
  40. package/src/pages-standard/plan-versions/types.ts +0 -33
  41. package/src/vue/use-plan-versions.ts +0 -83
package/dist/index.cjs CHANGED
@@ -65,7 +65,7 @@ __export(src_exports, {
65
65
  buildQuotaRegistry: () => buildQuotaRegistry,
66
66
  buildRoutes: () => buildRoutes,
67
67
  buildSidebar: () => buildSidebar,
68
- buildSnapshots: () => buildSnapshots,
68
+ createAdminResourceClient: () => createAdminResourceClient,
69
69
  createAdminRoutes: () => createAdminRoutes,
70
70
  createManifestStore: () => createManifestStore,
71
71
  createPlatformLoaders: () => createPlatformLoaders,
@@ -81,7 +81,6 @@ __export(src_exports, {
81
81
  formatCurrency: () => formatCurrency,
82
82
  formatMessage: () => formatMessage,
83
83
  getJson: () => getJson,
84
- listOpenDrafts: () => listOpenDrafts,
85
84
  mergeMessages: () => mergeMessages,
86
85
  postJson: () => postJson,
87
86
  provideEntitlement: () => provideEntitlement,
@@ -106,7 +105,6 @@ __export(src_exports, {
106
105
  useNav: () => useNav,
107
106
  usePlanEditor: () => usePlanEditor,
108
107
  usePlanVersions: () => usePlanVersions,
109
- usePlanVersionsCatalog: () => usePlanVersionsCatalog,
110
108
  usePlans: () => usePlans,
111
109
  usePlatformTenantActions: () => usePlatformTenantActions,
112
110
  usePromotions: () => usePromotions,
@@ -349,7 +347,6 @@ var navMessages = defineMessages(
349
347
  subscriptions: "Abonnements",
350
348
  promoCodes: "Promo-Codes",
351
349
  plans: "Pl\xE4ne & Versionen",
352
- planVersions: "Plan-Versionen",
353
350
  audit: "Audit-Log",
354
351
  users: "Benutzer",
355
352
  pilots: "Piloten",
@@ -373,7 +370,6 @@ var navMessages = defineMessages(
373
370
  subscriptions: "Subscriptions",
374
371
  promoCodes: "Promo codes",
375
372
  plans: "Plans & versions",
376
- planVersions: "Plan versions",
377
373
  audit: "Audit log",
378
374
  users: "Users",
379
375
  pilots: "Pilots",
@@ -399,7 +395,6 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
399
395
  subscriptions: "/admin/subscriptions",
400
396
  promoCodes: "/admin/promo-codes",
401
397
  plans: "/admin/plans",
402
- planVersions: "/admin/plan-versions",
403
398
  audit: "/admin/audit",
404
399
  users: "/admin/users",
405
400
  pilots: "/admin/pilots",
@@ -409,13 +404,15 @@ var DEFAULT_STANDARD_PAGE_ROUTES = {
409
404
  platformEmail: "/admin/platform-email",
410
405
  platformEmailHistory: "/admin/platform-email-history"
411
406
  };
407
+ function isSupportedStandardPageKey(key) {
408
+ return Object.hasOwn(DEFAULT_STANDARD_PAGE_ROUTES, key);
409
+ }
412
410
  var DEFAULT_ICONS = {
413
411
  dashboard: "dashboard",
414
412
  tenants: "business",
415
413
  subscriptions: "card_membership",
416
414
  promoCodes: "local_activity",
417
415
  plans: "workspace_premium",
418
- planVersions: "history_edu",
419
416
  audit: "history",
420
417
  users: "people",
421
418
  pilots: "flight_takeoff",
@@ -430,7 +427,6 @@ var PAGE_SECTIONS = {
430
427
  discovery: "catalog",
431
428
  bundles: "catalog",
432
429
  plans: "catalog",
433
- planVersions: "catalog",
434
430
  marketingCatalog: "catalog",
435
431
  promoCodes: "catalog",
436
432
  tenants: "customers",
@@ -458,6 +454,7 @@ function buildRoutes(manifest, options = {}) {
458
454
  const overrideIcons = { ...DEFAULT_ICONS, ...options.standardPageIcons };
459
455
  const overrideNavSection = { ...defaultNavSections, ...options.standardPageNavSection };
460
456
  for (const key of Object.keys(standard)) {
457
+ if (!isSupportedStandardPageKey(key)) continue;
461
458
  const def = standard[key];
462
459
  if (!def?.enabled) continue;
463
460
  const cap = def.requiredCapability ?? null;
@@ -698,471 +695,83 @@ var BatchColumnFetcher = class {
698
695
  }
699
696
  };
700
697
 
701
- // src/client/i18n/format.ts
702
- function formatMessage(template, params) {
703
- return template.replace(/\{(\w+)\}/g, (match, name) => {
704
- const value = params[name];
705
- return value === void 0 ? match : String(value);
706
- });
707
- }
708
-
709
- // src/client/i18n/messages/plan-versions.ts
710
- var planVersionsMessages = defineMessages(
711
- {
712
- compareEnd: "Vergleich beenden",
713
- page: {
714
- loadingCatalog: "Catalog wird geladen\u2026",
715
- noAuditLoader: "Kein Audit-Loader konfiguriert."
716
- },
717
- header: {
718
- modeList: "Plan-Liste",
719
- modeMatrix: "Feature-Matrix",
720
- modeAudit: "Aktivit\xE4t",
721
- publishedOn: "Publiziert {date}",
722
- openDrafts: "offene Drafts",
723
- regressionOne: "Regression",
724
- regressionMany: "Regressionen",
725
- startPublishFlow: "Publish-Flow starten",
726
- compareModeHint: "Vergleichsmodus aktiv \u2014 andere Ansichten deaktiviert"
727
- },
728
- status: {
729
- draft: "DRAFT",
730
- active: "AKTIV",
731
- archived: "ARCHIV"
732
- },
733
- timeline: {
734
- title: "Plan-Catalog",
735
- snapshotCount: "{count} Snapshots",
736
- noOpenDrafts: "keine offenen Drafts",
737
- openCount: "{count} offen",
738
- unknown: "unbekannt",
739
- compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
740
- },
741
- list: {
742
- kpiPlans: "Pakete",
743
- kpiSelfService: "Self-Service",
744
- kpiOfTotal: "von {count}",
745
- kpiFeaturesTotal: "Features gesamt",
746
- missingPlansLabel: "Fehlende Pakete:",
747
- missingPlansHint: "\u2014 keine Live-Version in diesem Snapshot.",
748
- createDraftFor: "Draft f\xFCr {planId}",
749
- colPlan: "Paket",
750
- colPriceNet: "Preis (netto)",
751
- colFeatures: "Features",
752
- draftHintLabel: "Arbeitsstand:",
753
- draftHintBefore: "Drafts oben in der Liste. Limits, Preise und Features per Klick auf",
754
- draftHintEditButton: '\u201EBearbeiten"',
755
- draftHintMiddle: "\xE4ndern (ohne MFA). Erst",
756
- draftHintPublishFlow: "Publish-Flow",
757
- draftHintAfter: "(Validate \u2192 Diff-Review \u2192 MFA \u2192 Apply) macht sie f\xFCr k\xFCnftige Renewals wirksam."
758
- },
759
- matrix: {
760
- colFeature: "Feature",
761
- perMonthShort: "/Mo",
762
- fallbackGroup: "Sonstige"
763
- },
764
- diff: {
765
- legend: "Vergleich",
766
- plansChanged: "Pakete ge\xE4ndert",
767
- regressions: "Regressionen",
768
- sectionPlans: "Pakete",
769
- changeCountOne: "{count} \xC4nderung",
770
- changeCountMany: "{count} \xC4nderungen"
771
- },
772
- diffPreview: {
773
- empty: "Keine \xC4nderungen gegen\xFCber der Vorg\xE4ngerversion.",
774
- improvement: "Verbesserung",
775
- regression: "Verschlechterung",
776
- neutral: "Neutral"
777
- },
778
- diffFields: {
779
- featuresAdded: "Hinzugef\xFCgte Features",
780
- featuresRemoved: "Entfernte Features",
781
- maxUsers: "Max. Benutzer",
782
- maxStorageGb: "Speicher (GB)",
783
- monthlyNet: "Preis monatlich (netto)",
784
- yearlyNet: "Preis j\xE4hrlich (netto)",
785
- unitSize: "Einheitsgr\xF6\xDFe"
786
- },
787
- audit: {
788
- title: "Aktivit\xE4t",
789
- eventCount: "{count} Events",
790
- loading: "Audit-Trail wird geladen\u2026",
791
- empty: "Keine Plan-/Add-on-Events im Audit-Log gefunden.",
792
- actionPlanPublished: "Plan publiziert",
793
- actionPlanDraftCreated: "Plan-Draft angelegt",
794
- actionPlanDraftUpdated: "Plan-Draft ge\xE4ndert",
795
- actionPlanDraftDeleted: "Plan-Draft gel\xF6scht",
796
- actionCatalogPublished: "Catalog publiziert",
797
- detailRegression: "Mit mindestens einer Verschlechterung publiziert.",
798
- detailFieldsChanged: "{count} Felder ge\xE4ndert."
799
- },
800
- bulkPublish: {
801
- changeNoteRequired: "changeNote ist Pflicht beim Publish."
802
- },
803
- format: {
804
- priceIndividual: "individuell",
805
- today: "heute",
806
- yesterday: "gestern",
807
- daysAgo: "vor {count} Tagen",
808
- weeksAgoOne: "vor {count} Woche",
809
- weeksAgoMany: "vor {count} Wochen",
810
- monthsAgo: "vor {count} Monaten",
811
- yearsAgoOne: "vor {count} Jahr",
812
- yearsAgoMany: "vor {count} Jahren"
813
- },
814
- catalog: {
815
- draftsLabel: "Arbeitsstand",
816
- draftsTitleEmpty: "Keine offenen Drafts",
817
- draftsTitleOne: "{count} offener Draft bereit f\xFCr Publish",
818
- draftsTitleMany: "{count} offene Drafts bereit f\xFCr Publish",
819
- draftsDescriptionEmpty: "Lege einen Draft an, um Limits, Preise oder Features zu \xE4ndern. Drafts sind ohne MFA editierbar und werden erst beim Publish wirksam.",
820
- draftsDescription: "Diese Tabelle zeigt, wie der Catalog nach Publish aller Drafts aussehen w\xFCrde. Bestehende Mandanten bleiben auf der vorherigen Version, bis sie aktiv migriert werden.",
821
- activeLabel: "Aktuell",
822
- activeTitle: "Live-Catalog",
823
- activeDescription: "Diese Plan-Versionen sind aktuell f\xFCr neue Onboardings und f\xFCr Renewals nach Stichtag aktiv.",
824
- publishEvent: "Publish-Event",
825
- publishEventSingle: "{planId} v{version} publiziert",
826
- publishEventMultiple: "{count} Versionen publiziert",
827
- reconstructedSnapshot: "Snapshot rekonstruiert aus per-Entity-Versionen."
828
- }
829
- },
830
- {
831
- compareEnd: "End comparison",
832
- page: {
833
- loadingCatalog: "Loading catalog\u2026",
834
- noAuditLoader: "No audit loader configured."
835
- },
836
- header: {
837
- modeList: "Plan list",
838
- modeMatrix: "Feature matrix",
839
- modeAudit: "Activity",
840
- publishedOn: "Published {date}",
841
- openDrafts: "open drafts",
842
- regressionOne: "regression",
843
- regressionMany: "regressions",
844
- startPublishFlow: "Start publish flow",
845
- compareModeHint: "Comparison mode active \u2014 other views disabled"
846
- },
847
- status: {
848
- draft: "DRAFT",
849
- active: "ACTIVE",
850
- archived: "ARCHIVED"
851
- },
852
- timeline: {
853
- title: "Plan catalog",
854
- snapshotCount: "{count} snapshots",
855
- noOpenDrafts: "no open drafts",
856
- openCount: "{count} open",
857
- unknown: "unknown",
858
- compareHint: "Right-click a snapshot \u2192 compare"
859
- },
860
- list: {
861
- kpiPlans: "Plans",
862
- kpiSelfService: "Self-service",
863
- kpiOfTotal: "of {count}",
864
- kpiFeaturesTotal: "Features total",
865
- missingPlansLabel: "Missing plans:",
866
- missingPlansHint: "\u2014 no live version in this snapshot.",
867
- createDraftFor: "Draft for {planId}",
868
- colPlan: "Plan",
869
- colPriceNet: "Price (net)",
870
- colFeatures: "Features",
871
- draftHintLabel: "Working state:",
872
- draftHintBefore: "Drafts at the top of the list. Change limits, prices and features by clicking",
873
- draftHintEditButton: '"Edit"',
874
- draftHintMiddle: "(without MFA). Only the",
875
- draftHintPublishFlow: "publish flow",
876
- draftHintAfter: "(validate \u2192 diff review \u2192 MFA \u2192 apply) makes them effective for future renewals."
877
- },
878
- matrix: {
879
- colFeature: "Feature",
880
- perMonthShort: "/mo",
881
- fallbackGroup: "Other"
882
- },
883
- diff: {
884
- legend: "Comparison",
885
- plansChanged: "Plans changed",
886
- regressions: "Regressions",
887
- sectionPlans: "Plans",
888
- changeCountOne: "{count} change",
889
- changeCountMany: "{count} changes"
890
- },
891
- diffPreview: {
892
- empty: "No changes compared to the previous version.",
893
- improvement: "Improvement",
894
- regression: "Regression",
895
- neutral: "Neutral"
896
- },
897
- diffFields: {
898
- featuresAdded: "Added features",
899
- featuresRemoved: "Removed features",
900
- maxUsers: "Max. users",
901
- maxStorageGb: "Storage (GB)",
902
- monthlyNet: "Price monthly (net)",
903
- yearlyNet: "Price yearly (net)",
904
- unitSize: "Unit size"
905
- },
906
- audit: {
907
- title: "Activity",
908
- eventCount: "{count} events",
909
- loading: "Loading audit trail\u2026",
910
- empty: "No plan/add-on events found in the audit log.",
911
- actionPlanPublished: "Plan published",
912
- actionPlanDraftCreated: "Plan draft created",
913
- actionPlanDraftUpdated: "Plan draft changed",
914
- actionPlanDraftDeleted: "Plan draft deleted",
915
- actionCatalogPublished: "Catalog published",
916
- detailRegression: "Published with at least one regression.",
917
- detailFieldsChanged: "{count} fields changed."
918
- },
919
- bulkPublish: {
920
- changeNoteRequired: "changeNote is required when publishing."
921
- },
922
- format: {
923
- priceIndividual: "custom",
924
- today: "today",
925
- yesterday: "yesterday",
926
- daysAgo: "{count} days ago",
927
- weeksAgoOne: "{count} week ago",
928
- weeksAgoMany: "{count} weeks ago",
929
- monthsAgo: "{count} months ago",
930
- yearsAgoOne: "{count} year ago",
931
- yearsAgoMany: "{count} years ago"
932
- },
933
- catalog: {
934
- draftsLabel: "Working state",
935
- draftsTitleEmpty: "No open drafts",
936
- draftsTitleOne: "{count} open draft ready to publish",
937
- draftsTitleMany: "{count} open drafts ready to publish",
938
- draftsDescriptionEmpty: "Create a draft to change limits, prices or features. Drafts are editable without MFA and only take effect when published.",
939
- draftsDescription: "This table shows what the catalog would look like after publishing all drafts. Existing tenants stay on the previous version until they are actively migrated.",
940
- activeLabel: "Current",
941
- activeTitle: "Live catalog",
942
- activeDescription: "These plan versions are currently active for new onboardings and for renewals after the effective date.",
943
- publishEvent: "Publish event",
944
- publishEventSingle: "{planId} v{version} published",
945
- publishEventMultiple: "{count} versions published",
946
- reconstructedSnapshot: "Snapshot reconstructed from per-entity versions."
947
- }
948
- }
949
- );
950
-
951
- // src/client/plan-versions-catalog.ts
952
- var dec = (s) => Number(s);
953
- function extractQuotas(p) {
954
- if (p.quotas && Object.keys(p.quotas).length > 0) {
955
- return { ...p.quotas };
956
- }
957
- const out = {};
958
- if (typeof p.maxUsers === "number") out.users = p.maxUsers;
959
- if (typeof p.maxVehicles === "number") out.vehicles = p.maxVehicles;
960
- if (typeof p.maxStorageGb === "number") out.storageGb = p.maxStorageGb;
961
- return out;
962
- }
963
- var sortByPublishedDesc = (rows) => [...rows].sort((a, b) => {
964
- const at = a.publishedAt ? Date.parse(a.publishedAt) : Number.POSITIVE_INFINITY;
965
- const bt = b.publishedAt ? Date.parse(b.publishedAt) : Number.POSITIVE_INFINITY;
966
- if (at !== bt) return bt - at;
967
- return b.version - a.version;
968
- });
969
- function findLiveAt(rows, asOfMs) {
970
- const candidates = rows.filter((r) => {
971
- if (r.publishedAt === null) return false;
972
- if (Date.parse(r.publishedAt) > asOfMs) return false;
973
- if (r.supersededAt !== null && Date.parse(r.supersededAt) <= asOfMs) return false;
974
- return true;
975
- });
976
- if (candidates.length === 0) return null;
977
- return [...candidates].sort((a, b) => b.version - a.version)[0] ?? null;
978
- }
979
- function findCurrentLive(rows) {
980
- return rows.find((r) => r.publishedAt !== null && r.supersededAt === null) ?? null;
981
- }
982
- function findDraft(rows) {
983
- return rows.find((r) => r.publishedAt === null) ?? null;
984
- }
985
- function groupBy(rows, keyOf) {
986
- const out = /* @__PURE__ */ new Map();
987
- for (const r of rows) {
988
- const k = keyOf(r);
989
- const list = out.get(k) ?? [];
990
- list.push(r);
991
- out.set(k, list);
992
- }
993
- return out;
994
- }
995
- function resolvePlan(source, liveBase) {
996
- const quotas = extractQuotas(source);
997
- return {
998
- source,
999
- liveBase,
1000
- isDraft: source.publishedAt === null,
1001
- planId: source.planId,
1002
- features: source.features,
1003
- quotas,
1004
- monthlyNet: dec(source.monthlyNet),
1005
- yearlyNet: dec(source.yearlyNet),
1006
- marketed: source.marketed,
1007
- version: source.version,
1008
- maxUsers: quotas.users,
1009
- maxVehicles: quotas.vehicles,
1010
- maxStorageGb: quotas.storageGb
698
+ // src/client/admin-resource-client.ts
699
+ function createAdminResourceClient(options) {
700
+ const base = options.adminBase ?? "/api/v1/admin";
701
+ const tenantsEndpoint = `${base}/tenants`;
702
+ const getJson2 = async (url) => {
703
+ const response = await options.http(url, { method: "GET" });
704
+ assertSuccess(response.status, "GET", url);
705
+ return await response.json();
1011
706
  };
1012
- }
1013
- function draftsTitle(draftCount, msg) {
1014
- if (draftCount === 0) return msg.draftsTitleEmpty;
1015
- const template = draftCount === 1 ? msg.draftsTitleOne : msg.draftsTitleMany;
1016
- return formatMessage(template, { count: draftCount });
1017
- }
1018
- function dateLabel(iso, locale) {
1019
- return new Date(iso).toLocaleDateString(SA_INTL_LOCALES[locale], {
1020
- day: "2-digit",
1021
- month: "short",
1022
- year: "numeric"
1023
- });
1024
- }
1025
- function buildDraftsSnapshot(data, sortPlansFn, locale) {
1026
- const msg = planVersionsMessages[locale].catalog;
1027
- const planByKey = groupBy(data.planVersions, (r) => r.planId);
1028
- const plans = [];
1029
- for (const [, rows] of planByKey) {
1030
- const draft = findDraft(rows);
1031
- const live = findCurrentLive(rows);
1032
- if (draft) plans.push(resolvePlan(draft, live));
1033
- else if (live) plans.push(resolvePlan(live, null));
1034
- }
1035
- const draftCount = plans.filter((p) => p.isDraft).length;
1036
- return {
1037
- id: "drafts",
1038
- kind: "drafts",
1039
- status: "DRAFT",
1040
- label: msg.draftsLabel,
1041
- title: draftsTitle(draftCount, msg),
1042
- description: draftCount === 0 ? msg.draftsDescriptionEmpty : msg.draftsDescription,
1043
- asOf: null,
1044
- createdAt: null,
1045
- publishedAt: null,
1046
- authorEmail: null,
1047
- plans: sortPlansFn(plans),
1048
- draftCount,
1049
- regressionCount: 0
707
+ const sendJson = async (method, url, body) => {
708
+ const response = await options.http(url, {
709
+ method,
710
+ headers: { "content-type": "application/json" },
711
+ body: body === void 0 ? void 0 : JSON.stringify(body)
712
+ });
713
+ assertSuccess(response.status, method, url);
714
+ return await response.json();
1050
715
  };
1051
- }
1052
- function buildActiveSnapshot(data, sortPlansFn, locale) {
1053
- const msg = planVersionsMessages[locale].catalog;
1054
- const planByKey = groupBy(data.planVersions, (r) => r.planId);
1055
- const plans = [];
1056
- for (const [, rows] of planByKey) {
1057
- const live = findCurrentLive(rows);
1058
- if (live) plans.push(resolvePlan(live, null));
1059
- }
1060
- if (plans.length === 0) return null;
1061
- const publishedDates = plans.map((p) => p.source.publishedAt).filter((t) => t !== null).sort();
1062
- const latestPublished = publishedDates[publishedDates.length - 1];
1063
716
  return {
1064
- id: "active",
1065
- kind: "active",
1066
- status: "ACTIVE",
1067
- label: msg.activeLabel,
1068
- title: msg.activeTitle,
1069
- description: msg.activeDescription,
1070
- asOf: latestPublished ?? null,
1071
- createdAt: null,
1072
- publishedAt: latestPublished ?? null,
1073
- authorEmail: null,
1074
- plans: sortPlansFn(plans),
1075
- draftCount: 0,
1076
- regressionCount: 0
717
+ tenantsEndpoint,
718
+ loadTenantDetail: (slug) => getJson2(`${tenantsEndpoint}/${encodeURIComponent(slug)}`),
719
+ loadUsers: (filter) => getJson2(
720
+ `${base}/users${queryString({ q: filter.q, tenant: filter.tenant })}`
721
+ ),
722
+ loadAudit: (filter) => getJson2(
723
+ `${base}/audit${queryString({
724
+ actor: filter.actor,
725
+ action: filter.action,
726
+ entity: filter.entity,
727
+ since: filter.since,
728
+ limit: filter.limit
729
+ })}`
730
+ ),
731
+ loadSubscriptions: () => getJson2(`${base}/subscriptions`),
732
+ loadPromos: (filter) => getJson2(
733
+ `${base}/promo-codes${queryString({
734
+ search: filter.search,
735
+ status: filter.status
736
+ })}`
737
+ ),
738
+ createPromo: async (payload) => {
739
+ await sendJson("POST", `${base}/promo-codes`, payload);
740
+ },
741
+ updatePromo: async (id, payload) => {
742
+ await sendJson("PATCH", `${base}/promo-codes/${encodeURIComponent(id)}`, payload);
743
+ },
744
+ deletePromo: async (id) => {
745
+ await sendJson("DELETE", `${base}/promo-codes/${encodeURIComponent(id)}`);
746
+ },
747
+ suspendTenant: (slug, reason) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/suspend`, {
748
+ reason
749
+ }),
750
+ reactivateTenant: (slug) => sendJson("POST", `${tenantsEndpoint}/${encodeURIComponent(slug)}/reactivate`)
1077
751
  };
1078
752
  }
1079
- function buildHistoricalSnapshots(data, sortPlansFn, locale) {
1080
- const msg = planVersionsMessages[locale].catalog;
1081
- const allPublishedAt = /* @__PURE__ */ new Set();
1082
- for (const r of data.planVersions) if (r.publishedAt) allPublishedAt.add(r.publishedAt);
1083
- if (allPublishedAt.size === 0) return [];
1084
- const planByKey = groupBy(data.planVersions, (r) => r.planId);
1085
- const liveTimestamps = /* @__PURE__ */ new Set();
1086
- for (const rows of planByKey.values()) {
1087
- const live = findCurrentLive(rows);
1088
- if (live?.publishedAt) liveTimestamps.add(live.publishedAt);
1089
- }
1090
- const liveSorted = [...liveTimestamps].sort();
1091
- const latestLive = liveSorted[liveSorted.length - 1];
1092
- const sortedDesc = [...allPublishedAt].sort((a, b) => Date.parse(b) - Date.parse(a));
1093
- const out = [];
1094
- for (const ts of sortedDesc) {
1095
- if (latestLive && Date.parse(ts) >= Date.parse(latestLive)) continue;
1096
- const tMs = Date.parse(ts) + 1;
1097
- const plans = [];
1098
- for (const [, rows] of planByKey) {
1099
- const live = findLiveAt(rows, tMs);
1100
- if (live) plans.push(resolvePlan(live, null));
1101
- }
1102
- if (plans.length === 0) continue;
1103
- const publishedAtThisEvent = data.planVersions.filter((r) => r.publishedAt === ts);
1104
- const regressionCount = publishedAtThisEvent.filter((r) => !r.nonRegressive).length;
1105
- const author = publishedAtThisEvent[0]?.publishedByUserId ?? null;
1106
- out.push({
1107
- id: `hist-${ts}`,
1108
- kind: "historical",
1109
- status: "ARCHIVED",
1110
- label: dateLabel(ts, locale),
1111
- title: summarizeEvent(publishedAtThisEvent, msg),
1112
- description: detailEvent(publishedAtThisEvent, msg),
1113
- asOf: ts,
1114
- createdAt: ts,
1115
- publishedAt: ts,
1116
- authorEmail: author,
1117
- plans: sortPlansFn(plans),
1118
- draftCount: 0,
1119
- regressionCount
1120
- });
753
+ function assertSuccess(status, method, url) {
754
+ if (status < 200 || status >= 300) {
755
+ throw new Error(`${method} ${url} \u2192 HTTP ${status}`);
1121
756
  }
1122
- return out;
1123
757
  }
1124
- function summarizeEvent(rows, msg) {
1125
- if (rows.length === 0) return msg.publishEvent;
1126
- if (rows.length === 1) {
1127
- const r = rows[0];
1128
- return formatMessage(msg.publishEventSingle, { planId: r.planId, version: r.version });
1129
- }
1130
- return formatMessage(msg.publishEventMultiple, { count: rows.length });
758
+ function queryString(params) {
759
+ const search = new URLSearchParams();
760
+ for (const [key, value2] of Object.entries(params)) {
761
+ if (value2 === void 0 || value2 === null || value2 === "") continue;
762
+ search.set(key, String(value2));
763
+ }
764
+ const value = search.toString();
765
+ return value ? `?${value}` : "";
1131
766
  }
1132
- function detailEvent(rows, msg) {
1133
- if (rows.length === 0) return "";
1134
- const note = rows[0]?.changeNote ?? "";
1135
- return note.length > 0 ? note : msg.reconstructedSnapshot;
1136
- }
1137
- function sortPlansBy(order) {
1138
- if (!order || order.length === 0) {
1139
- return (rows) => [...rows].sort((a, b) => a.planId.localeCompare(b.planId));
1140
- }
1141
- const idx = {};
1142
- for (let i = 0; i < order.length; i++) idx[order[i]] = i;
1143
- return (rows) => [...rows].sort((a, b) => {
1144
- const ai = idx[a.planId] ?? Number.POSITIVE_INFINITY;
1145
- const bi = idx[b.planId] ?? Number.POSITIVE_INFINITY;
1146
- if (ai !== bi) return ai - bi;
1147
- return a.planId.localeCompare(b.planId);
767
+
768
+ // src/client/i18n/format.ts
769
+ function formatMessage(template, params) {
770
+ return template.replace(/\{(\w+)\}/g, (match, name) => {
771
+ const value = params[name];
772
+ return value === void 0 ? match : String(value);
1148
773
  });
1149
774
  }
1150
- function buildSnapshots(data, options = {}) {
1151
- const locale = options.locale ?? DEFAULT_SA_LOCALE;
1152
- const sortPlansFn = sortPlansBy(options.planSortOrder);
1153
- const drafts = buildDraftsSnapshot(data, sortPlansFn, locale);
1154
- const active = buildActiveSnapshot(data, sortPlansFn, locale);
1155
- const historical = buildHistoricalSnapshots(data, sortPlansFn, locale);
1156
- const out = [drafts];
1157
- if (active) out.push(active);
1158
- out.push(...historical);
1159
- return out;
1160
- }
1161
- function listOpenDrafts(data) {
1162
- return {
1163
- plans: sortByPublishedDesc(data.planVersions).filter((r) => r.publishedAt === null)
1164
- };
1165
- }
1166
775
 
1167
776
  // src/client/i18n/currency.ts
1168
777
  var DEFAULT_CURRENCY = "EUR";
@@ -3030,6 +2639,114 @@ var planEditorMessages = defineMessages(
3030
2639
  }
3031
2640
  );
3032
2641
 
2642
+ // src/client/i18n/messages/plan-versions.ts
2643
+ var planVersionsMessages = defineMessages(
2644
+ {
2645
+ compareEnd: "Vergleich beenden",
2646
+ status: {
2647
+ draft: "DRAFT",
2648
+ active: "AKTIV",
2649
+ archived: "ARCHIV"
2650
+ },
2651
+ timeline: {
2652
+ title: "Plan-Catalog",
2653
+ snapshotCount: "{count} Snapshots",
2654
+ noOpenDrafts: "keine offenen Drafts",
2655
+ openCount: "{count} offen",
2656
+ unknown: "unbekannt",
2657
+ compareHint: "Rechtsklick auf Snapshot \u2192 vergleichen"
2658
+ },
2659
+ diff: {
2660
+ legend: "Vergleich",
2661
+ plansChanged: "Pakete ge\xE4ndert",
2662
+ regressions: "Regressionen",
2663
+ sectionPlans: "Pakete",
2664
+ changeCountOne: "{count} \xC4nderung",
2665
+ changeCountMany: "{count} \xC4nderungen"
2666
+ },
2667
+ diffPreview: {
2668
+ empty: "Keine \xC4nderungen gegen\xFCber der Vorg\xE4ngerversion.",
2669
+ improvement: "Verbesserung",
2670
+ regression: "Verschlechterung",
2671
+ neutral: "Neutral"
2672
+ },
2673
+ diffFields: {
2674
+ featuresAdded: "Hinzugef\xFCgte Features",
2675
+ featuresRemoved: "Entfernte Features",
2676
+ maxUsers: "Max. Benutzer",
2677
+ maxStorageGb: "Speicher (GB)",
2678
+ monthlyNet: "Preis monatlich (netto)",
2679
+ yearlyNet: "Preis j\xE4hrlich (netto)",
2680
+ unitSize: "Einheitsgr\xF6\xDFe"
2681
+ },
2682
+ bulkPublish: {
2683
+ changeNoteRequired: "changeNote ist Pflicht beim Publish."
2684
+ },
2685
+ format: {
2686
+ today: "heute",
2687
+ yesterday: "gestern",
2688
+ daysAgo: "vor {count} Tagen",
2689
+ weeksAgoOne: "vor {count} Woche",
2690
+ weeksAgoMany: "vor {count} Wochen",
2691
+ monthsAgo: "vor {count} Monaten",
2692
+ yearsAgoOne: "vor {count} Jahr",
2693
+ yearsAgoMany: "vor {count} Jahren"
2694
+ }
2695
+ },
2696
+ {
2697
+ compareEnd: "End comparison",
2698
+ status: {
2699
+ draft: "DRAFT",
2700
+ active: "ACTIVE",
2701
+ archived: "ARCHIVED"
2702
+ },
2703
+ timeline: {
2704
+ title: "Plan catalog",
2705
+ snapshotCount: "{count} snapshots",
2706
+ noOpenDrafts: "no open drafts",
2707
+ openCount: "{count} open",
2708
+ unknown: "unknown",
2709
+ compareHint: "Right-click a snapshot \u2192 compare"
2710
+ },
2711
+ diff: {
2712
+ legend: "Comparison",
2713
+ plansChanged: "Plans changed",
2714
+ regressions: "Regressions",
2715
+ sectionPlans: "Plans",
2716
+ changeCountOne: "{count} change",
2717
+ changeCountMany: "{count} changes"
2718
+ },
2719
+ diffPreview: {
2720
+ empty: "No changes compared to the previous version.",
2721
+ improvement: "Improvement",
2722
+ regression: "Regression",
2723
+ neutral: "Neutral"
2724
+ },
2725
+ diffFields: {
2726
+ featuresAdded: "Added features",
2727
+ featuresRemoved: "Removed features",
2728
+ maxUsers: "Max. users",
2729
+ maxStorageGb: "Storage (GB)",
2730
+ monthlyNet: "Price monthly (net)",
2731
+ yearlyNet: "Price yearly (net)",
2732
+ unitSize: "Unit size"
2733
+ },
2734
+ bulkPublish: {
2735
+ changeNoteRequired: "changeNote is required when publishing."
2736
+ },
2737
+ format: {
2738
+ today: "today",
2739
+ yesterday: "yesterday",
2740
+ daysAgo: "{count} days ago",
2741
+ weeksAgoOne: "{count} week ago",
2742
+ weeksAgoMany: "{count} weeks ago",
2743
+ monthsAgo: "{count} months ago",
2744
+ yearsAgoOne: "{count} year ago",
2745
+ yearsAgoMany: "{count} years ago"
2746
+ }
2747
+ }
2748
+ );
2749
+
3033
2750
  // src/client/i18n/messages/plans.ts
3034
2751
  var plansMessages = defineMessages(
3035
2752
  {
@@ -4877,30 +4594,8 @@ function useSubscriptionDraft(options) {
4877
4594
  };
4878
4595
  }
4879
4596
 
4880
- // src/vue/use-plan-versions.ts
4881
- var import_vue13 = require("vue");
4882
- function buildVersionsComposable(label) {
4883
- return function(options) {
4884
- if (!options?.endpoint) {
4885
- throw new Error(
4886
- `${label}: \`endpoint\` is required (e.g. "/api/admin/${label}" or "/api/v1/admin/${label}"). The platform has no default because apps use different globalPrefix conventions.`
4887
- );
4888
- }
4889
- const filter = options.filter ?? (0, import_vue13.ref)({});
4890
- const list = useApiList({
4891
- endpoint: options.endpoint,
4892
- filter,
4893
- http: options.http,
4894
- getAuthToken: options.getAuthToken,
4895
- autoLoad: options.autoLoad
4896
- });
4897
- return { ...list, filter };
4898
- };
4899
- }
4900
- var usePlanVersionsCatalog = buildVersionsComposable("plan-versions");
4901
-
4902
4597
  // src/vue/use-bulk-publish.ts
4903
- var import_vue14 = require("vue");
4598
+ var import_vue13 = require("vue");
4904
4599
  function useBulkPublish(options) {
4905
4600
  const msg = useSaMessages("planVersions");
4906
4601
  if (!options?.endpoints) {
@@ -4910,15 +4605,15 @@ function useBulkPublish(options) {
4910
4605
  }
4911
4606
  const http = options.http ?? defaultHttpClient();
4912
4607
  const endpoints = options.endpoints;
4913
- const items = (0, import_vue14.ref)([]);
4914
- const successCount = (0, import_vue14.computed)(() => items.value.filter((i) => i.status === "published").length);
4915
- const failureCount = (0, import_vue14.computed)(() => items.value.filter((i) => i.status === "failed").length);
4916
- const progress = (0, import_vue14.computed)(() => {
4608
+ const items = (0, import_vue13.ref)([]);
4609
+ const successCount = (0, import_vue13.computed)(() => items.value.filter((i) => i.status === "published").length);
4610
+ const failureCount = (0, import_vue13.computed)(() => items.value.filter((i) => i.status === "failed").length);
4611
+ const progress = (0, import_vue13.computed)(() => {
4917
4612
  if (items.value.length === 0) return 0;
4918
4613
  const done2 = successCount.value + failureCount.value;
4919
4614
  return done2 / items.value.length;
4920
4615
  });
4921
- const done = (0, import_vue14.computed)(
4616
+ const done = (0, import_vue13.computed)(
4922
4617
  () => items.value.length > 0 && items.value.every((i) => i.status === "published" || i.status === "failed")
4923
4618
  );
4924
4619
  function setItems(next) {
@@ -4976,7 +4671,7 @@ function useBulkPublish(options) {
4976
4671
  }
4977
4672
 
4978
4673
  // src/vue/use-plan-editor.ts
4979
- var import_vue15 = require("vue");
4674
+ var import_vue14 = require("vue");
4980
4675
  var PlannedOnlyFeatureError = class extends Error {
4981
4676
  constructor(violations) {
4982
4677
  super(
@@ -4996,10 +4691,10 @@ function tierWeight(tier) {
4996
4691
  function usePlanEditor(manifest, options = {}) {
4997
4692
  const baseSet = new Set(options.baseFeatures ?? []);
4998
4693
  const nonRegressive = options.nonRegressive ?? true;
4999
- const selectedFeatures = (0, import_vue15.ref)(new Set(options.initialFeatures ?? []));
4694
+ const selectedFeatures = (0, import_vue14.ref)(new Set(options.initialFeatures ?? []));
5000
4695
  const catalogFeatures = manifest.planCatalogSnapshot.features ?? [];
5001
4696
  const plannedOnlySet = new Set(catalogFeatures.filter((f) => f.plannedOnly).map((f) => f.key));
5002
- const availableFeatures = (0, import_vue15.computed)(() => {
4697
+ const availableFeatures = (0, import_vue14.computed)(() => {
5003
4698
  return catalogFeatures.map((def) => {
5004
4699
  const isSelected = selectedFeatures.value.has(def.key);
5005
4700
  const isPlannedOnly = !!def.plannedOnly;
@@ -5008,7 +4703,7 @@ function usePlanEditor(manifest, options = {}) {
5008
4703
  return { def, isSelected, isPlannedOnly, isInherited, canToggle };
5009
4704
  });
5010
4705
  });
5011
- const featuresByTier = (0, import_vue15.computed)(() => {
4706
+ const featuresByTier = (0, import_vue14.computed)(() => {
5012
4707
  const groups = /* @__PURE__ */ new Map();
5013
4708
  for (const row of availableFeatures.value) {
5014
4709
  const tier = row.def.tier ?? "OTHER";
@@ -5053,12 +4748,12 @@ function usePlanEditor(manifest, options = {}) {
5053
4748
  }
5054
4749
 
5055
4750
  // src/vue/use-public-boot.ts
5056
- var import_vue16 = require("vue");
4751
+ var import_vue15 = require("vue");
5057
4752
  function usePublicBoot(options) {
5058
4753
  const loader = new BootLoader(options);
5059
- const boot = (0, import_vue16.ref)(null);
5060
- const loading = (0, import_vue16.ref)(false);
5061
- const error = (0, import_vue16.ref)(null);
4754
+ const boot = (0, import_vue15.ref)(null);
4755
+ const loading = (0, import_vue15.ref)(false);
4756
+ const error = (0, import_vue15.ref)(null);
5062
4757
  async function load() {
5063
4758
  loading.value = true;
5064
4759
  error.value = null;
@@ -5075,7 +4770,7 @@ function usePublicBoot(options) {
5075
4770
  }
5076
4771
 
5077
4772
  // src/vue/use-discovery.ts
5078
- var import_vue17 = require("vue");
4773
+ var import_vue16 = require("vue");
5079
4774
  var DiscoveryLoadError = class extends Error {
5080
4775
  constructor(status, message) {
5081
4776
  super(message);
@@ -5092,10 +4787,10 @@ function useDiscovery(options) {
5092
4787
  );
5093
4788
  }
5094
4789
  const http = options.http ?? defaultHttpClient();
5095
- const snapshot = (0, import_vue17.ref)(null);
5096
- const etag = (0, import_vue17.ref)(null);
5097
- const loading = (0, import_vue17.ref)(false);
5098
- const error = (0, import_vue17.ref)(null);
4790
+ const snapshot = (0, import_vue16.ref)(null);
4791
+ const etag = (0, import_vue16.ref)(null);
4792
+ const loading = (0, import_vue16.ref)(false);
4793
+ const error = (0, import_vue16.ref)(null);
5099
4794
  async function fetchSnapshot(includeEtag) {
5100
4795
  loading.value = true;
5101
4796
  error.value = null;
@@ -5162,7 +4857,7 @@ function useDiscovery(options) {
5162
4857
  }
5163
4858
 
5164
4859
  // src/vue/use-catalog-entries.ts
5165
- var import_vue18 = require("vue");
4860
+ var import_vue17 = require("vue");
5166
4861
  var CatalogEntriesApiError = class extends Error {
5167
4862
  constructor(status, body, message) {
5168
4863
  super(message);
@@ -5182,11 +4877,11 @@ function useCatalogEntries(options) {
5182
4877
  }
5183
4878
  const msg = useSaMessages("discovery");
5184
4879
  const http = options.http ?? defaultHttpClient();
5185
- const capabilities = (0, import_vue18.ref)([]);
5186
- const features = (0, import_vue18.ref)([]);
5187
- const quotas = (0, import_vue18.ref)([]);
5188
- const loading = (0, import_vue18.ref)(false);
5189
- const error = (0, import_vue18.ref)(null);
4880
+ const capabilities = (0, import_vue17.ref)([]);
4881
+ const features = (0, import_vue17.ref)([]);
4882
+ const quotas = (0, import_vue17.ref)([]);
4883
+ const loading = (0, import_vue17.ref)(false);
4884
+ const error = (0, import_vue17.ref)(null);
5190
4885
  const base = `${options.adminEndpoint}/catalog`;
5191
4886
  const pk = encodeURIComponent(options.projectKey);
5192
4887
  function authHeaders() {
@@ -5312,7 +5007,7 @@ function useCatalogEntries(options) {
5312
5007
  }
5313
5008
 
5314
5009
  // src/vue/use-bundles.ts
5315
- var import_vue19 = require("vue");
5010
+ var import_vue18 = require("vue");
5316
5011
  var BundlesApiError = class extends Error {
5317
5012
  constructor(status, body, message) {
5318
5013
  super(message);
@@ -5333,9 +5028,9 @@ function useBundles(options) {
5333
5028
  throw new Error("useBundles: `projectKey` is required.");
5334
5029
  }
5335
5030
  const http = options.http ?? defaultHttpClient();
5336
- const bundles = (0, import_vue19.ref)([]);
5337
- const loading = (0, import_vue19.ref)(false);
5338
- const error = (0, import_vue19.ref)(null);
5031
+ const bundles = (0, import_vue18.ref)([]);
5032
+ const loading = (0, import_vue18.ref)(false);
5033
+ const error = (0, import_vue18.ref)(null);
5339
5034
  const baseUrl = `${options.adminEndpoint}/catalog/bundles`;
5340
5035
  function authHeaders() {
5341
5036
  const token = options.getAuthToken?.();
@@ -5407,9 +5102,9 @@ function useBundleVersions(options) {
5407
5102
  throw new Error("useBundleVersions: `bundleId` is required.");
5408
5103
  }
5409
5104
  const http = options.http ?? defaultHttpClient();
5410
- const versions = (0, import_vue19.ref)([]);
5411
- const loading = (0, import_vue19.ref)(false);
5412
- const error = (0, import_vue19.ref)(null);
5105
+ const versions = (0, import_vue18.ref)([]);
5106
+ const loading = (0, import_vue18.ref)(false);
5107
+ const error = (0, import_vue18.ref)(null);
5413
5108
  const bundleVersionsUrl = `${options.adminEndpoint}/catalog/bundles/${options.bundleId}/versions`;
5414
5109
  const versionUrlBase = `${options.adminEndpoint}/catalog/bundle-versions`;
5415
5110
  function authHeaders() {
@@ -5483,7 +5178,7 @@ function useBundleVersions(options) {
5483
5178
  }
5484
5179
 
5485
5180
  // src/vue/use-bundle-versions-map.ts
5486
- var import_vue20 = require("vue");
5181
+ var import_vue19 = require("vue");
5487
5182
  function useBundleVersionsMap(options) {
5488
5183
  if (!options?.adminEndpoint) {
5489
5184
  throw new Error("useBundleVersionsMap: `adminEndpoint` is required.");
@@ -5492,9 +5187,9 @@ function useBundleVersionsMap(options) {
5492
5187
  throw new Error("useBundleVersionsMap: `bundles` is required.");
5493
5188
  }
5494
5189
  const http = options.http ?? defaultHttpClient();
5495
- const versionsByBundle = (0, import_vue20.ref)({});
5496
- const loading = (0, import_vue20.ref)(false);
5497
- const error = (0, import_vue20.ref)(null);
5190
+ const versionsByBundle = (0, import_vue19.ref)({});
5191
+ const loading = (0, import_vue19.ref)(false);
5192
+ const error = (0, import_vue19.ref)(null);
5498
5193
  function authHeaders() {
5499
5194
  const token = options.getAuthToken?.();
5500
5195
  return token ? { Authorization: `Bearer ${token}` } : {};
@@ -5544,7 +5239,7 @@ function useBundleVersionsMap(options) {
5544
5239
  console.warn(`useBundleVersionsMap: refreshOne('${bundleId}') failed`, err);
5545
5240
  }
5546
5241
  }
5547
- (0, import_vue20.watch)(
5242
+ (0, import_vue19.watch)(
5548
5243
  () => options.bundles.value.map((b) => b.id).join(","),
5549
5244
  () => {
5550
5245
  if (options.bundles.value.length > 0) void refresh();
@@ -5556,7 +5251,7 @@ function useBundleVersionsMap(options) {
5556
5251
  }
5557
5252
 
5558
5253
  // src/vue/use-tenant-subscription-bundles.ts
5559
- var import_vue21 = require("vue");
5254
+ var import_vue20 = require("vue");
5560
5255
  var TenantSubscriptionBundlesApiError = class extends Error {
5561
5256
  constructor(status, body, message) {
5562
5257
  super(message);
@@ -5575,9 +5270,9 @@ function useTenantSubscriptionBundles(options) {
5575
5270
  }
5576
5271
  const http = options.http ?? defaultHttpClient();
5577
5272
  const baseUrl = `${options.billingEndpoint}/billing/subscription-bundles`;
5578
- const bundles = (0, import_vue21.ref)([]);
5579
- const loading = (0, import_vue21.ref)(false);
5580
- const error = (0, import_vue21.ref)(null);
5273
+ const bundles = (0, import_vue20.ref)([]);
5274
+ const loading = (0, import_vue20.ref)(false);
5275
+ const error = (0, import_vue20.ref)(null);
5581
5276
  function authHeaders() {
5582
5277
  const token = options.getAuthToken?.();
5583
5278
  return token ? { Authorization: `Bearer ${token}` } : {};
@@ -5651,7 +5346,7 @@ function rehydrateDates(raw) {
5651
5346
  }
5652
5347
 
5653
5348
  // src/vue/use-marketing-projections.ts
5654
- var import_vue22 = require("vue");
5349
+ var import_vue21 = require("vue");
5655
5350
  var MarketingProjectionsApiError = class extends Error {
5656
5351
  constructor(status, body, message) {
5657
5352
  super(message);
@@ -5671,10 +5366,10 @@ function useMarketingProjections(options) {
5671
5366
  }
5672
5367
  const msg = useSaMessages("marketing");
5673
5368
  const http = options.http ?? defaultHttpClient();
5674
- const projections = (0, import_vue22.ref)([]);
5675
- const filter = (0, import_vue22.ref)({ ...options.filter });
5676
- const loading = (0, import_vue22.ref)(false);
5677
- const error = (0, import_vue22.ref)(null);
5369
+ const projections = (0, import_vue21.ref)([]);
5370
+ const filter = (0, import_vue21.ref)({ ...options.filter });
5371
+ const loading = (0, import_vue21.ref)(false);
5372
+ const error = (0, import_vue21.ref)(null);
5678
5373
  const baseUrl = `${options.adminEndpoint}/catalog/marketing-projections`;
5679
5374
  function authHeaders() {
5680
5375
  const token = options.getAuthToken?.();
@@ -5755,7 +5450,7 @@ function useMarketingProjections(options) {
5755
5450
  }
5756
5451
 
5757
5452
  // src/vue/use-promotions.ts
5758
- var import_vue23 = require("vue");
5453
+ var import_vue22 = require("vue");
5759
5454
  var PromotionsApiError = class extends Error {
5760
5455
  constructor(status, body, message) {
5761
5456
  super(message);
@@ -5775,9 +5470,9 @@ function usePromotions(options) {
5775
5470
  }
5776
5471
  const msg = useSaMessages("promos");
5777
5472
  const http = options.http ?? defaultHttpClient();
5778
- const promotions = (0, import_vue23.ref)([]);
5779
- const loading = (0, import_vue23.ref)(false);
5780
- const error = (0, import_vue23.ref)(null);
5473
+ const promotions = (0, import_vue22.ref)([]);
5474
+ const loading = (0, import_vue22.ref)(false);
5475
+ const error = (0, import_vue22.ref)(null);
5781
5476
  const baseUrl = `${options.adminEndpoint}/catalog/promotions`;
5782
5477
  const pk = encodeURIComponent(options.projectKey);
5783
5478
  function authHeaders() {
@@ -5842,7 +5537,7 @@ function usePromotions(options) {
5842
5537
  }
5843
5538
 
5844
5539
  // src/vue/use-plans.ts
5845
- var import_vue24 = require("vue");
5540
+ var import_vue23 = require("vue");
5846
5541
  var PlansApiError = class extends Error {
5847
5542
  constructor(status, body, message) {
5848
5543
  super(message);
@@ -5863,10 +5558,10 @@ function usePlans(options) {
5863
5558
  throw new Error("usePlans: `projectKey` is required.");
5864
5559
  }
5865
5560
  const http = options.http ?? defaultHttpClient();
5866
- const plans = (0, import_vue24.ref)([]);
5867
- const loading = (0, import_vue24.ref)(false);
5868
- const error = (0, import_vue24.ref)(null);
5869
- const tenantCountsByPlanKey = (0, import_vue24.ref)({});
5561
+ const plans = (0, import_vue23.ref)([]);
5562
+ const loading = (0, import_vue23.ref)(false);
5563
+ const error = (0, import_vue23.ref)(null);
5564
+ const tenantCountsByPlanKey = (0, import_vue23.ref)({});
5870
5565
  const baseUrl = `${options.adminEndpoint}/catalog/plans`;
5871
5566
  function authHeaders() {
5872
5567
  const token = options.getAuthToken?.();
@@ -5967,9 +5662,9 @@ function usePlanVersions(options) {
5967
5662
  throw new Error("usePlanVersions: `planId` is required.");
5968
5663
  }
5969
5664
  const http = options.http ?? defaultHttpClient();
5970
- const versions = (0, import_vue24.ref)([]);
5971
- const loading = (0, import_vue24.ref)(false);
5972
- const error = (0, import_vue24.ref)(null);
5665
+ const versions = (0, import_vue23.ref)([]);
5666
+ const loading = (0, import_vue23.ref)(false);
5667
+ const error = (0, import_vue23.ref)(null);
5973
5668
  const planVersionsUrl = `${options.adminEndpoint}/catalog/plans/${options.planId}/versions`;
5974
5669
  const versionUrlBase = `${options.adminEndpoint}/catalog/plan-versions`;
5975
5670
  function authHeaders() {
@@ -6066,7 +5761,7 @@ function usePlanVersions(options) {
6066
5761
  }
6067
5762
 
6068
5763
  // src/vue/use-live-plan-versions.ts
6069
- var import_vue25 = require("vue");
5764
+ var import_vue24 = require("vue");
6070
5765
  function useLivePlanVersions(options) {
6071
5766
  if (!options?.adminEndpoint) {
6072
5767
  throw new Error("useLivePlanVersions: `adminEndpoint` is required.");
@@ -6075,9 +5770,9 @@ function useLivePlanVersions(options) {
6075
5770
  throw new Error("useLivePlanVersions: `plans` is required.");
6076
5771
  }
6077
5772
  const http = options.http ?? defaultHttpClient();
6078
- const livePlanVersions = (0, import_vue25.ref)({});
6079
- const loading = (0, import_vue25.ref)(false);
6080
- const error = (0, import_vue25.ref)(null);
5773
+ const livePlanVersions = (0, import_vue24.ref)({});
5774
+ const loading = (0, import_vue24.ref)(false);
5775
+ const error = (0, import_vue24.ref)(null);
6081
5776
  function authHeaders() {
6082
5777
  const token = options.getAuthToken?.();
6083
5778
  return token ? { Authorization: `Bearer ${token}` } : {};
@@ -6119,7 +5814,7 @@ function useLivePlanVersions(options) {
6119
5814
  loading.value = false;
6120
5815
  }
6121
5816
  }
6122
- (0, import_vue25.watch)(
5817
+ (0, import_vue24.watch)(
6123
5818
  () => options.plans.value.map((p) => p.id).join(","),
6124
5819
  () => {
6125
5820
  if (options.plans.value.length > 0) void refresh();
@@ -6141,12 +5836,12 @@ function findLatestLive(versions) {
6141
5836
  }
6142
5837
 
6143
5838
  // src/vue/use-manifest.ts
6144
- var import_vue26 = require("vue");
5839
+ var import_vue25 = require("vue");
6145
5840
  function useManifest(options) {
6146
5841
  const loader = new ManifestLoader(options);
6147
- const manifest = (0, import_vue26.ref)(null);
6148
- const loading = (0, import_vue26.ref)(false);
6149
- const error = (0, import_vue26.ref)(null);
5842
+ const manifest = (0, import_vue25.ref)(null);
5843
+ const loading = (0, import_vue25.ref)(false);
5844
+ const error = (0, import_vue25.ref)(null);
6150
5845
  async function load() {
6151
5846
  loading.value = true;
6152
5847
  error.value = null;
@@ -6172,24 +5867,24 @@ function useManifest(options) {
6172
5867
  }
6173
5868
 
6174
5869
  // src/vue/use-nav.ts
6175
- var import_vue27 = require("vue");
5870
+ var import_vue26 = require("vue");
6176
5871
  function useNav(manifest, options = {}) {
6177
5872
  const { locale } = useSuperAdminI18n();
6178
- const activeLocale = (0, import_vue27.computed)(() => options.locale ?? locale.value);
6179
- const routes = (0, import_vue27.computed)(() => {
5873
+ const activeLocale = (0, import_vue26.computed)(() => options.locale ?? locale.value);
5874
+ const routes = (0, import_vue26.computed)(() => {
6180
5875
  if (!manifest.value) return [];
6181
5876
  return buildRoutes(manifest.value, { ...options, locale: activeLocale.value });
6182
5877
  });
6183
- const sidebar = (0, import_vue27.computed)(
5878
+ const sidebar = (0, import_vue26.computed)(
6184
5879
  () => buildSidebar(routes.value, defaultSectionOrder(activeLocale.value))
6185
5880
  );
6186
5881
  return { routes, sidebar };
6187
5882
  }
6188
5883
 
6189
5884
  // src/vue/use-actions.ts
6190
- var import_vue28 = require("vue");
5885
+ var import_vue27 = require("vue");
6191
5886
  function useActions(manifest, actions) {
6192
- const registry = (0, import_vue28.computed)(() => {
5887
+ const registry = (0, import_vue27.computed)(() => {
6193
5888
  if (!manifest.value) return null;
6194
5889
  return new ActionRegistry(manifest.value, actions);
6195
5890
  });
@@ -6197,18 +5892,18 @@ function useActions(manifest, actions) {
6197
5892
  }
6198
5893
 
6199
5894
  // src/vue/use-tenant-action-flow.ts
6200
- var import_vue29 = require("vue");
5895
+ var import_vue28 = require("vue");
6201
5896
  function useTenantActionFlow(manifest, providers = {}) {
6202
5897
  const handlers = useSuperAdminActions();
6203
5898
  const msg = useSaMessages("tenants");
6204
- const registry = (0, import_vue29.computed)(() => {
5899
+ const registry = (0, import_vue28.computed)(() => {
6205
5900
  if (!manifest.value) return null;
6206
5901
  return new ActionRegistry(manifest.value, handlers);
6207
5902
  });
6208
- const orphanedDefs = (0, import_vue29.computed)(
5903
+ const orphanedDefs = (0, import_vue28.computed)(
6209
5904
  () => registry.value ? registry.value.listOrphanedDefs() : []
6210
5905
  );
6211
- const availableActions = (0, import_vue29.computed)(() => {
5906
+ const availableActions = (0, import_vue28.computed)(() => {
6212
5907
  const m = manifest.value;
6213
5908
  const reg = registry.value;
6214
5909
  if (!m || !reg) return [];
@@ -6281,7 +5976,7 @@ async function runFlow(def, row, registry, providers, successTemplate) {
6281
5976
  }
6282
5977
 
6283
5978
  // src/vue/use-platform-tenant-actions.ts
6284
- var import_vue30 = require("vue");
5979
+ var import_vue29 = require("vue");
6285
5980
  var DEFAULT_VISIBLE_FOR_ROW = (def, row) => {
6286
5981
  if (def.actionKey === "tenants.suspend") return row.isActive;
6287
5982
  if (def.actionKey === "tenants.reactivate") return !row.isActive;
@@ -6317,7 +6012,7 @@ function usePlatformTenantActions(options) {
6317
6012
  const iconForActionKey = options.iconForActionKey ?? DEFAULT_ICON_FOR_ACTION_KEY;
6318
6013
  const toneForActionKey = options.toneForActionKey ?? DEFAULT_TONE_FOR_ACTION_KEY;
6319
6014
  const visibleForRow = options.visibleForRow ?? DEFAULT_VISIBLE_FOR_ROW;
6320
- const mfa = (0, import_vue30.ref)({ show: false, description: "", error: "" });
6015
+ const mfa = (0, import_vue29.ref)({ show: false, description: "", error: "" });
6321
6016
  let pendingMfaResolve = null;
6322
6017
  function showMfaDialog(def, ctx) {
6323
6018
  return new Promise((resolve) => {
@@ -6342,7 +6037,7 @@ function usePlatformTenantActions(options) {
6342
6037
  pendingMfaResolve(null);
6343
6038
  }
6344
6039
  }
6345
- const confirmDialog = (0, import_vue30.ref)({
6040
+ const confirmDialog = (0, import_vue29.ref)({
6346
6041
  show: false,
6347
6042
  def: null,
6348
6043
  row: null
@@ -6384,7 +6079,7 @@ function usePlatformTenantActions(options) {
6384
6079
  },
6385
6080
  visibleForRow
6386
6081
  });
6387
- const manifestActions = (0, import_vue30.computed)(
6082
+ const manifestActions = (0, import_vue29.computed)(
6388
6083
  () => flow.availableActions.value.map((def) => ({
6389
6084
  id: def.id,
6390
6085
  label: def.label,
@@ -6398,7 +6093,7 @@ function usePlatformTenantActions(options) {
6398
6093
  }
6399
6094
  }))
6400
6095
  );
6401
- const realOrphans = (0, import_vue30.computed)(() => {
6096
+ const realOrphans = (0, import_vue29.computed)(() => {
6402
6097
  const caps = options.manifest.value?.capabilities ?? {};
6403
6098
  const defs = options.manifest.value?.tenants?.actions ?? [];
6404
6099
  const defByActionKey = new Map(defs.map((d) => [d.actionKey, d]));
@@ -6423,12 +6118,12 @@ function usePlatformTenantActions(options) {
6423
6118
  }
6424
6119
 
6425
6120
  // src/vue/use-batch-columns.ts
6426
- var import_vue31 = require("vue");
6121
+ var import_vue30 = require("vue");
6427
6122
  function useBatchColumns(manifest, tenantIds, options = {}) {
6428
6123
  const fetcher = new BatchColumnFetcher(options);
6429
- const data = (0, import_vue31.ref)({});
6430
- const loading = (0, import_vue31.ref)(false);
6431
- const error = (0, import_vue31.ref)(null);
6124
+ const data = (0, import_vue30.ref)({});
6125
+ const loading = (0, import_vue30.ref)(false);
6126
+ const error = (0, import_vue30.ref)(null);
6432
6127
  async function load() {
6433
6128
  if (!manifest.value || tenantIds.value.length === 0) {
6434
6129
  data.value = {};
@@ -6445,7 +6140,7 @@ function useBatchColumns(manifest, tenantIds, options = {}) {
6445
6140
  loading.value = false;
6446
6141
  }
6447
6142
  }
6448
- (0, import_vue31.watch)([manifest, tenantIds], () => {
6143
+ (0, import_vue30.watch)([manifest, tenantIds], () => {
6449
6144
  void load();
6450
6145
  });
6451
6146
  return { data, loading, error, reload: load };
@@ -6477,13 +6172,13 @@ function createPlatformLoaders(options) {
6477
6172
 
6478
6173
  // src/vue/manifest-store-factory.ts
6479
6174
  var import_pinia = require("pinia");
6480
- var import_vue32 = require("vue");
6175
+ var import_vue31 = require("vue");
6481
6176
  function createManifestStore(options) {
6482
6177
  return (0, import_pinia.defineStore)(options.id ?? "admin-manifest", () => {
6483
- const manifest = (0, import_vue32.ref)(null);
6484
- const loading = (0, import_vue32.ref)(false);
6485
- const error = (0, import_vue32.ref)(null);
6486
- const loaded = (0, import_vue32.ref)(false);
6178
+ const manifest = (0, import_vue31.ref)(null);
6179
+ const loading = (0, import_vue31.ref)(false);
6180
+ const error = (0, import_vue31.ref)(null);
6181
+ const loaded = (0, import_vue31.ref)(false);
6487
6182
  let inflight = null;
6488
6183
  async function load() {
6489
6184
  loading.value = true;
@@ -6908,7 +6603,7 @@ function defaultTenantPlanSectionI18n(locale) {
6908
6603
  buildQuotaRegistry,
6909
6604
  buildRoutes,
6910
6605
  buildSidebar,
6911
- buildSnapshots,
6606
+ createAdminResourceClient,
6912
6607
  createAdminRoutes,
6913
6608
  createManifestStore,
6914
6609
  createPlatformLoaders,
@@ -6924,7 +6619,6 @@ function defaultTenantPlanSectionI18n(locale) {
6924
6619
  formatCurrency,
6925
6620
  formatMessage,
6926
6621
  getJson,
6927
- listOpenDrafts,
6928
6622
  mergeMessages,
6929
6623
  postJson,
6930
6624
  provideEntitlement,
@@ -6949,7 +6643,6 @@ function defaultTenantPlanSectionI18n(locale) {
6949
6643
  useNav,
6950
6644
  usePlanEditor,
6951
6645
  usePlanVersions,
6952
- usePlanVersionsCatalog,
6953
6646
  usePlans,
6954
6647
  usePlatformTenantActions,
6955
6648
  usePromotions,