@hai3/framework 0.2.0-alpha.0 → 0.2.0-alpha.2

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.
package/dist/index.js CHANGED
@@ -159,8 +159,8 @@ Add the missing plugin: .use(${depName}())`
159
159
  */
160
160
  createStoreWithSlices(slices) {
161
161
  const store = getStore();
162
- slices.forEach((slice9) => {
163
- registerSlice(slice9);
162
+ slices.forEach((slice10) => {
163
+ registerSlice(slice10);
164
164
  });
165
165
  return store;
166
166
  }
@@ -444,6 +444,25 @@ var tenantSlice = slice8;
444
444
  var tenantActions = { setTenant, setTenantLoading, clearTenant };
445
445
  var tenantSlice_default = slice8.reducer;
446
446
 
447
+ // src/slices/mockSlice.ts
448
+ import { createSlice as createSlice9 } from "@hai3/state";
449
+ var SLICE_KEY9 = "mock";
450
+ var initialState9 = {
451
+ enabled: false
452
+ };
453
+ var { slice: slice9, setMockEnabled } = createSlice9({
454
+ name: SLICE_KEY9,
455
+ initialState: initialState9,
456
+ reducers: {
457
+ setMockEnabled: (state, action) => {
458
+ state.enabled = action.payload;
459
+ }
460
+ }
461
+ });
462
+ var mockSlice = slice9;
463
+ var mockActions = { setMockEnabled };
464
+ var mockSlice_default = slice9.reducer;
465
+
447
466
  // src/slices/index.ts
448
467
  var LAYOUT_SLICE_NAME = "layout";
449
468
  var TENANT_SLICE_NAME = "app/tenant";
@@ -489,39 +508,34 @@ function screensets(config) {
489
508
  // src/plugins/themes.ts
490
509
  import { eventBus } from "@hai3/state";
491
510
 
492
- // src/compat.ts
493
- import { getStore as getStore2 } from "@hai3/state";
494
- import { apiRegistry as apiRegistry2 } from "@hai3/api";
495
- import { screensetRegistry as sdkScreensetRegistry2 } from "@hai3/screensets";
496
-
497
511
  // src/registries/themeRegistry.ts
498
- function createThemeRegistry() {
512
+ function createThemeRegistry(config) {
499
513
  const themes2 = /* @__PURE__ */ new Map();
500
- const legacyThemes = /* @__PURE__ */ new Map();
514
+ const uikitThemes = /* @__PURE__ */ new Map();
501
515
  let currentThemeId = null;
502
- let customApplyFn = null;
516
+ const customApplyFn = config?.applyFn ?? null;
503
517
  const subscribers = /* @__PURE__ */ new Set();
504
518
  let version = 0;
505
519
  function notifySubscribers() {
506
520
  version++;
507
521
  subscribers.forEach((callback) => callback());
508
522
  }
509
- function applyCSSVariables(config) {
523
+ function applyCSSVariables(config2) {
510
524
  if (typeof document === "undefined") return;
511
525
  const root = document.documentElement;
512
- Object.entries(config.variables).forEach(([key, value]) => {
526
+ Object.entries(config2.variables).forEach(([key, value]) => {
513
527
  root.style.setProperty(key, value);
514
528
  });
515
529
  }
516
530
  return {
517
531
  /**
518
532
  * Register a theme.
519
- * Supports both new API (config only) and legacy API (id + theme).
533
+ * Supports both config-based API and UIKit theme API.
520
534
  */
521
- register(configOrId, legacyTheme) {
535
+ register(configOrId, uikitTheme) {
522
536
  if (typeof configOrId === "string") {
523
537
  const id = configOrId;
524
- if (!legacyTheme) {
538
+ if (!uikitTheme) {
525
539
  console.warn(`register() called with ID "${id}" but no theme object. Skipping.`);
526
540
  return;
527
541
  }
@@ -529,39 +543,33 @@ function createThemeRegistry() {
529
543
  console.warn(`Theme "${id}" is already registered. Skipping.`);
530
544
  return;
531
545
  }
532
- legacyThemes.set(id, legacyTheme);
546
+ uikitThemes.set(id, uikitTheme);
533
547
  let themeName = id;
534
- if (legacyTheme && typeof legacyTheme === "object" && "name" in legacyTheme) {
535
- const nameValue = legacyTheme.name;
548
+ if (uikitTheme && typeof uikitTheme === "object" && "name" in uikitTheme) {
549
+ const nameValue = uikitTheme.name;
536
550
  if (typeof nameValue === "string") {
537
551
  themeName = nameValue;
538
552
  }
539
553
  }
540
- const config2 = {
554
+ const config3 = {
541
555
  id,
542
556
  name: themeName,
543
557
  variables: {}
544
- // Legacy themes use custom apply function
558
+ // UIKit themes use custom apply function
545
559
  };
546
- themes2.set(id, config2);
560
+ themes2.set(id, config3);
547
561
  return;
548
562
  }
549
- const config = configOrId;
550
- if (themes2.has(config.id)) {
551
- console.warn(`Theme "${config.id}" is already registered. Skipping.`);
563
+ const config2 = configOrId;
564
+ if (themes2.has(config2.id)) {
565
+ console.warn(`Theme "${config2.id}" is already registered. Skipping.`);
552
566
  return;
553
567
  }
554
- themes2.set(config.id, config);
555
- if (config.default && currentThemeId === null) {
556
- this.apply(config.id);
568
+ themes2.set(config2.id, config2);
569
+ if (config2.default && currentThemeId === null) {
570
+ this.apply(config2.id);
557
571
  }
558
572
  },
559
- /**
560
- * Set the apply function (legacy API).
561
- */
562
- setApplyFunction(applyFn) {
563
- customApplyFn = applyFn;
564
- },
565
573
  /**
566
574
  * Get theme by ID.
567
575
  */
@@ -578,16 +586,17 @@ function createThemeRegistry() {
578
586
  * Apply a theme.
579
587
  */
580
588
  apply(id) {
581
- const config = themes2.get(id);
582
- if (!config) {
589
+ const config2 = themes2.get(id);
590
+ if (!config2) {
583
591
  console.warn(`Theme "${id}" not found. Cannot apply.`);
584
592
  return;
585
593
  }
586
- const legacyTheme = legacyThemes.get(id);
587
- if (legacyTheme && customApplyFn) {
588
- customApplyFn(legacyTheme, id);
589
- } else if (config.variables && Object.keys(config.variables).length > 0) {
590
- applyCSSVariables(config);
594
+ if (config2.variables && Object.keys(config2.variables).length > 0) {
595
+ applyCSSVariables(config2);
596
+ }
597
+ const uikitTheme = uikitThemes.get(id);
598
+ if (uikitTheme && customApplyFn) {
599
+ customApplyFn(uikitTheme, id);
591
600
  }
592
601
  currentThemeId = id;
593
602
  notifySubscribers();
@@ -618,117 +627,18 @@ function createThemeRegistry() {
618
627
  };
619
628
  }
620
629
 
621
- // src/registries/routeRegistry.ts
622
- function createRouteRegistry(screensetRegistry3) {
623
- let routes = null;
624
- function buildRoutes() {
625
- if (routes !== null) {
626
- return routes;
627
- }
628
- routes = [];
629
- const screensets2 = screensetRegistry3.getAll();
630
- screensets2.forEach((screenset) => {
631
- screenset.menu.forEach((menuScreenItem) => {
632
- const screenId = menuScreenItem.menuItem.screenId ?? menuScreenItem.menuItem.id;
633
- if (screenId && menuScreenItem.screen) {
634
- routes.push({
635
- screensetId: screenset.id,
636
- screenId,
637
- loader: menuScreenItem.screen
638
- });
639
- }
640
- });
641
- });
642
- return routes;
643
- }
644
- return {
645
- /**
646
- * Check if a screen exists by screenId only (globally unique).
647
- */
648
- hasScreenById(screenId) {
649
- const allRoutes = buildRoutes();
650
- return allRoutes.some((route) => route.screenId === screenId);
651
- },
652
- /**
653
- * Check if a screen exists (legacy, requires both IDs).
654
- */
655
- hasScreen(screensetId, screenId) {
656
- const allRoutes = buildRoutes();
657
- return allRoutes.some(
658
- (route) => route.screensetId === screensetId && route.screenId === screenId
659
- );
660
- },
661
- /**
662
- * Get screenset ID for a given screen ID (reverse lookup).
663
- * Screen IDs are globally unique across all screensets.
664
- */
665
- getScreensetForScreen(screenId) {
666
- const allRoutes = buildRoutes();
667
- const route = allRoutes.find((r) => r.screenId === screenId);
668
- return route?.screensetId;
669
- },
670
- /**
671
- * Get screen loader by screenId only.
672
- */
673
- getScreenById(screenId) {
674
- const allRoutes = buildRoutes();
675
- const route = allRoutes.find((r) => r.screenId === screenId);
676
- return route?.loader;
677
- },
678
- /**
679
- * Get screen loader (legacy, requires both IDs).
680
- */
681
- getScreen(screensetId, screenId) {
682
- const allRoutes = buildRoutes();
683
- const route = allRoutes.find(
684
- (r) => r.screensetId === screensetId && r.screenId === screenId
685
- );
686
- return route?.loader;
687
- },
688
- /**
689
- * Get all routes.
690
- */
691
- getAll() {
692
- const allRoutes = buildRoutes();
693
- return allRoutes.map(({ screensetId, screenId }) => ({
694
- screensetId,
695
- screenId
696
- }));
697
- }
698
- };
699
- }
700
-
701
- // src/compat.ts
702
- import { screensetRegistry } from "@hai3/screensets";
703
- var screenActions3 = screenActions;
704
- var ACCOUNTS_DOMAIN = "accounts";
705
- var themeRegistry = createThemeRegistry();
706
- var routeRegistry = createRouteRegistry(sdkScreensetRegistry2);
707
- var navigateToScreen = (screenId) => {
708
- getStore2().dispatch(screenActions3.setActiveScreen(screenId));
709
- };
710
- var fetchCurrentUser = () => (_dispatch) => {
711
- try {
712
- const accountsService = apiRegistry2.getService(ACCOUNTS_DOMAIN);
713
- const service = accountsService;
714
- service.getCurrentUser?.();
715
- } catch {
716
- console.warn("fetchCurrentUser: accounts service not registered");
717
- }
718
- };
719
-
720
630
  // src/plugins/themes.ts
721
631
  function changeTheme(payload) {
722
632
  eventBus.emit("theme/changed", payload);
723
633
  }
724
- function themes() {
725
- const themeRegistry2 = themeRegistry;
634
+ function themes(config) {
635
+ const themeRegistry = createThemeRegistry(config);
726
636
  return {
727
637
  name: "themes",
728
638
  dependencies: [],
729
639
  provides: {
730
640
  registries: {
731
- themeRegistry: themeRegistry2
641
+ themeRegistry
732
642
  },
733
643
  actions: {
734
644
  changeTheme
@@ -736,11 +646,11 @@ function themes() {
736
646
  },
737
647
  onInit(_app) {
738
648
  eventBus.on("theme/changed", (payload) => {
739
- themeRegistry2.apply(payload.themeId);
649
+ themeRegistry.apply(payload.themeId);
740
650
  });
741
- const themes2 = themeRegistry2.getAll();
651
+ const themes2 = themeRegistry.getAll();
742
652
  if (themes2.length > 0) {
743
- themeRegistry2.apply(themes2[0].id);
653
+ themeRegistry.apply(themes2[0].id);
744
654
  }
745
655
  }
746
656
  };
@@ -837,60 +747,124 @@ function layout() {
837
747
  // src/plugins/navigation.ts
838
748
  import { eventBus as eventBus3 } from "@hai3/state";
839
749
  import { i18nRegistry } from "@hai3/i18n";
840
- var screenActions4 = screenActions;
841
- var menuActions3 = menuActions;
842
- function buildMenuItems(screenset) {
843
- return screenset.menu.map((item) => ({
844
- id: item.menuItem.screenId ?? item.menuItem.id,
845
- label: item.menuItem.label,
846
- icon: item.menuItem.icon
847
- }));
750
+
751
+ // src/utils/basePath.ts
752
+ function normalizeBase(base) {
753
+ if (!base) {
754
+ return "/";
755
+ }
756
+ let normalized = base.startsWith("/") ? base : `/${base}`;
757
+ if (normalized !== "/" && normalized.endsWith("/")) {
758
+ normalized = normalized.slice(0, -1);
759
+ }
760
+ return normalized;
761
+ }
762
+ function stripBase(pathname, base) {
763
+ if (base === "/") {
764
+ return pathname;
765
+ }
766
+ if (!pathname.startsWith(base)) {
767
+ return null;
768
+ }
769
+ const nextChar = pathname.charAt(base.length);
770
+ if (nextChar && nextChar !== "/") {
771
+ return null;
772
+ }
773
+ return pathname.slice(base.length) || "/";
848
774
  }
849
- function navigateToScreen2(payload) {
775
+ function prependBase(path, base) {
776
+ if (base === "/") {
777
+ return path;
778
+ }
779
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
780
+ return `${base}${cleanPath}`;
781
+ }
782
+ function resolveBase(pluginConfig, appConfig) {
783
+ const rawBase = pluginConfig?.base ?? appConfig?.base ?? "/";
784
+ return normalizeBase(rawBase);
785
+ }
786
+
787
+ // src/plugins/navigation.ts
788
+ var screenActions3 = screenActions;
789
+ var menuActions3 = menuActions;
790
+ function navigateToScreen(payload) {
850
791
  eventBus3.emit("navigation/screen/navigated", payload);
851
792
  }
852
793
  function navigateToScreenset(payload) {
853
794
  eventBus3.emit("navigation/screenset/navigated", payload);
854
795
  }
855
- function navigation() {
796
+ function navigation(config) {
856
797
  return {
857
798
  name: "navigation",
858
799
  dependencies: ["screensets"],
859
800
  provides: {
860
801
  actions: {
861
- navigateToScreen: navigateToScreen2,
802
+ navigateToScreen,
862
803
  navigateToScreenset
863
804
  }
864
805
  },
865
806
  onInit(app) {
866
807
  const dispatch = app.store.dispatch;
808
+ const base = resolveBase(config, app.config);
867
809
  let currentScreensetId = null;
868
- async function loadScreensetTranslations(screensetId, language) {
869
- await i18nRegistry.loadScreensetTranslations(screensetId, language);
870
- }
871
- function updateMenuForScreenset(screensetId) {
872
- if (screensetId === currentScreensetId) return;
810
+ const loadScreensetTranslations = async (screensetId, language) => {
811
+ await i18nRegistry.loadScreensetTranslations(
812
+ screensetId,
813
+ language
814
+ );
815
+ };
816
+ const updateScreensetMenu = (screenset) => {
817
+ const menuItems = screenset.menu.map((item) => ({
818
+ id: item.menuItem.screenId ?? item.menuItem.id,
819
+ label: item.menuItem.label,
820
+ icon: item.menuItem.icon
821
+ }));
822
+ dispatch(menuActions3.setMenuItems(menuItems));
823
+ };
824
+ const activateScreenset = (screensetId) => {
825
+ if (screensetId === currentScreensetId) {
826
+ return;
827
+ }
873
828
  const screenset = app.screensetRegistry.get(screensetId);
874
- if (!screenset) return;
829
+ if (!screenset) {
830
+ return;
831
+ }
875
832
  currentScreensetId = screensetId;
876
833
  loadScreensetTranslations(screensetId).catch((err) => {
877
834
  console.warn(`[HAI3] Failed to load translations for screenset ${screensetId}:`, err);
878
835
  });
879
- const menuItems = buildMenuItems(screenset);
880
- dispatch(menuActions3.setMenuItems(menuItems));
881
- }
836
+ updateScreensetMenu(screenset);
837
+ };
838
+ const extractScreenId = () => {
839
+ const internalPath = stripBase(window.location.pathname, base);
840
+ if (!internalPath) {
841
+ return null;
842
+ }
843
+ const parts = internalPath.split("/").filter(Boolean);
844
+ return parts[0] || null;
845
+ };
846
+ const activateScreen = (screenId) => {
847
+ const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
848
+ if (!screensetId) {
849
+ return;
850
+ }
851
+ activateScreenset(screensetId);
852
+ dispatch(screenActions3.navigateTo(screenId));
853
+ };
882
854
  eventBus3.on("navigation/screen/navigated", (payload) => {
883
- if (app.routeRegistry && !app.routeRegistry.hasScreen(payload.screensetId, payload.screenId)) {
855
+ if (!app.routeRegistry?.hasScreen(payload.screensetId, payload.screenId)) {
884
856
  console.warn(
885
857
  `Screen "${payload.screenId}" in screenset "${payload.screensetId}" not found.`
886
858
  );
887
859
  return;
888
860
  }
889
- updateMenuForScreenset(payload.screensetId);
890
- dispatch(screenActions4.navigateTo(payload.screenId));
861
+ activateScreenset(payload.screensetId);
862
+ dispatch(screenActions3.navigateTo(payload.screenId));
891
863
  if (typeof window !== "undefined") {
892
- const url = `/${payload.screenId}`;
893
- window.history.pushState(null, "", url);
864
+ const url = prependBase(`/${payload.screenId}`, base);
865
+ if (window.location.pathname !== url) {
866
+ window.history.pushState(null, "", url);
867
+ }
894
868
  }
895
869
  });
896
870
  eventBus3.on("navigation/screenset/navigated", (payload) => {
@@ -899,7 +873,7 @@ function navigation() {
899
873
  console.warn(`Screenset "${payload.screensetId}" not found.`);
900
874
  return;
901
875
  }
902
- navigateToScreen2({
876
+ navigateToScreen({
903
877
  screensetId: payload.screensetId,
904
878
  screenId: screenset.defaultScreen
905
879
  });
@@ -907,15 +881,18 @@ function navigation() {
907
881
  let lastLoadedLanguage = null;
908
882
  i18nRegistry.subscribe(() => {
909
883
  const currentLanguage = i18nRegistry.getLanguage();
910
- if (!currentLanguage || currentLanguage === lastLoadedLanguage) return;
911
- if (!currentScreensetId) return;
884
+ if (!currentLanguage || currentLanguage === lastLoadedLanguage) {
885
+ return;
886
+ }
887
+ if (!currentScreensetId) {
888
+ return;
889
+ }
912
890
  const screenset = app.screensetRegistry.get(currentScreensetId);
913
- if (!screenset) return;
891
+ if (!screenset) {
892
+ return;
893
+ }
914
894
  lastLoadedLanguage = currentLanguage;
915
- loadScreensetTranslations(currentScreensetId, currentLanguage).then(() => {
916
- const menuItems = buildMenuItems(screenset);
917
- dispatch(menuActions3.setMenuItems(menuItems));
918
- }).catch((err) => {
895
+ loadScreensetTranslations(currentScreensetId, currentLanguage).then(() => updateScreensetMenu(screenset)).catch((err) => {
919
896
  console.warn(
920
897
  `[HAI3] Failed to reload translations for screenset ${currentScreensetId}:`,
921
898
  err
@@ -924,31 +901,15 @@ function navigation() {
924
901
  });
925
902
  if (typeof window !== "undefined") {
926
903
  window.addEventListener("popstate", () => {
927
- const path2 = window.location.pathname;
928
- const parts2 = path2.split("/").filter(Boolean);
929
- if (parts2.length >= 1) {
930
- const screenId = parts2[0];
931
- const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
932
- if (screensetId) {
933
- updateMenuForScreenset(screensetId);
934
- dispatch(screenActions4.navigateTo(screenId));
935
- }
904
+ const screenId2 = extractScreenId();
905
+ if (screenId2) {
906
+ activateScreen(screenId2);
936
907
  }
937
908
  });
938
- const path = window.location.pathname;
939
- const parts = path.split("/").filter(Boolean);
909
+ const screenId = extractScreenId();
940
910
  const autoNavigate = app.config.autoNavigate !== false;
941
- if (parts.length >= 1) {
942
- const screenId = parts[0];
943
- const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
944
- if (screensetId) {
945
- navigateToScreen2({ screensetId, screenId });
946
- } else if (autoNavigate) {
947
- const screensets2 = app.screensetRegistry.getAll();
948
- if (screensets2.length > 0) {
949
- navigateToScreenset({ screensetId: screensets2[0].id });
950
- }
951
- }
911
+ if (screenId) {
912
+ activateScreen(screenId);
952
913
  } else if (autoNavigate) {
953
914
  const screensets2 = app.screensetRegistry.getAll();
954
915
  if (screensets2.length > 0) {
@@ -960,6 +921,86 @@ function navigation() {
960
921
  };
961
922
  }
962
923
 
924
+ // src/registries/routeRegistry.ts
925
+ function createRouteRegistry(screensetRegistry3) {
926
+ let routes = null;
927
+ function buildRoutes() {
928
+ if (routes !== null) {
929
+ return routes;
930
+ }
931
+ routes = [];
932
+ const screensets2 = screensetRegistry3.getAll();
933
+ screensets2.forEach((screenset) => {
934
+ screenset.menu.forEach((menuScreenItem) => {
935
+ const screenId = menuScreenItem.menuItem.screenId ?? menuScreenItem.menuItem.id;
936
+ if (screenId && menuScreenItem.screen) {
937
+ routes.push({
938
+ screensetId: screenset.id,
939
+ screenId,
940
+ loader: menuScreenItem.screen
941
+ });
942
+ }
943
+ });
944
+ });
945
+ return routes;
946
+ }
947
+ return {
948
+ /**
949
+ * Check if a screen exists by screenId only (globally unique).
950
+ */
951
+ hasScreenById(screenId) {
952
+ const allRoutes = buildRoutes();
953
+ return allRoutes.some((route) => route.screenId === screenId);
954
+ },
955
+ /**
956
+ * Check if a screen exists by both screensetId and screenId (explicit lookup when screenset context is known).
957
+ */
958
+ hasScreen(screensetId, screenId) {
959
+ const allRoutes = buildRoutes();
960
+ return allRoutes.some(
961
+ (route) => route.screensetId === screensetId && route.screenId === screenId
962
+ );
963
+ },
964
+ /**
965
+ * Get screenset ID for a given screen ID (reverse lookup).
966
+ * Screen IDs are globally unique across all screensets.
967
+ */
968
+ getScreensetForScreen(screenId) {
969
+ const allRoutes = buildRoutes();
970
+ const route = allRoutes.find((r) => r.screenId === screenId);
971
+ return route?.screensetId;
972
+ },
973
+ /**
974
+ * Get screen loader by screenId only.
975
+ */
976
+ getScreenById(screenId) {
977
+ const allRoutes = buildRoutes();
978
+ const route = allRoutes.find((r) => r.screenId === screenId);
979
+ return route?.loader;
980
+ },
981
+ /**
982
+ * Get screen loader by both screensetId and screenId (explicit lookup when screenset context is known).
983
+ */
984
+ getScreen(screensetId, screenId) {
985
+ const allRoutes = buildRoutes();
986
+ const route = allRoutes.find(
987
+ (r) => r.screensetId === screensetId && r.screenId === screenId
988
+ );
989
+ return route?.loader;
990
+ },
991
+ /**
992
+ * Get all routes.
993
+ */
994
+ getAll() {
995
+ const allRoutes = buildRoutes();
996
+ return allRoutes.map(({ screensetId, screenId }) => ({
997
+ screensetId,
998
+ screenId
999
+ }));
1000
+ }
1001
+ };
1002
+ }
1003
+
963
1004
  // src/plugins/routing.ts
964
1005
  function routing() {
965
1006
  return {
@@ -968,8 +1009,8 @@ function routing() {
968
1009
  onRegister(_app) {
969
1010
  },
970
1011
  onInit(app) {
971
- const routeRegistry2 = createRouteRegistry(app.screensetRegistry);
972
- app.routeRegistry = routeRegistry2;
1012
+ const routeRegistry = createRouteRegistry(app.screensetRegistry);
1013
+ app.routeRegistry = routeRegistry;
973
1014
  }
974
1015
  };
975
1016
  }
@@ -1017,16 +1058,101 @@ function effects() {
1017
1058
  };
1018
1059
  }
1019
1060
 
1061
+ // src/effects/mockEffects.ts
1062
+ import { eventBus as eventBus5, getStore as getStore2 } from "@hai3/state";
1063
+ import { apiRegistry as apiRegistry2, isMockPlugin } from "@hai3/api";
1064
+ function hasPluginManagement(protocol) {
1065
+ return "plugins" in protocol && typeof protocol.plugins === "object";
1066
+ }
1067
+ var MockEvents = {
1068
+ Toggle: "mock/toggle"
1069
+ };
1070
+ function syncMockPlugins(enabled) {
1071
+ for (const service of apiRegistry2.getAll()) {
1072
+ const registeredPlugins = service.getPlugins();
1073
+ for (const [protocol, plugins] of registeredPlugins) {
1074
+ if (!hasPluginManagement(protocol)) continue;
1075
+ for (const plugin of plugins) {
1076
+ if (isMockPlugin(plugin)) {
1077
+ if (enabled) {
1078
+ const existingPlugins = protocol.plugins.getAll();
1079
+ if (!existingPlugins.includes(plugin)) {
1080
+ protocol.plugins.add(plugin);
1081
+ }
1082
+ } else {
1083
+ protocol.plugins.remove(plugin);
1084
+ }
1085
+ }
1086
+ }
1087
+ }
1088
+ }
1089
+ }
1090
+ function initMockEffects() {
1091
+ const store = getStore2();
1092
+ const unsubscribe = eventBus5.on(MockEvents.Toggle, (payload) => {
1093
+ store.dispatch(setMockEnabled(payload.enabled));
1094
+ syncMockPlugins(payload.enabled);
1095
+ });
1096
+ const currentState = store.getState();
1097
+ if ("mock" in currentState && currentState.mock && typeof currentState.mock === "object" && "enabled" in currentState.mock) {
1098
+ syncMockPlugins(currentState.mock.enabled);
1099
+ }
1100
+ return () => {
1101
+ unsubscribe.unsubscribe();
1102
+ };
1103
+ }
1104
+ function toggleMockMode(enabled) {
1105
+ eventBus5.emit(MockEvents.Toggle, { enabled });
1106
+ }
1107
+
1108
+ // src/plugins/mock.ts
1109
+ var cleanup = null;
1110
+ function isDevEnvironment() {
1111
+ if (typeof window === "undefined") return false;
1112
+ const { hostname } = window.location;
1113
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".local");
1114
+ }
1115
+ function mock(config) {
1116
+ return {
1117
+ name: "mock",
1118
+ dependencies: ["effects"],
1119
+ provides: {
1120
+ slices: [mockSlice],
1121
+ actions: {
1122
+ toggleMockMode
1123
+ }
1124
+ },
1125
+ onInit() {
1126
+ cleanup = initMockEffects();
1127
+ const isDev = isDevEnvironment();
1128
+ const enabledByDefault = config?.enabledByDefault ?? isDev;
1129
+ if (enabledByDefault) {
1130
+ toggleMockMode(true);
1131
+ if (isDev) {
1132
+ console.log("[HAI3] Mock mode enabled by default (dev environment detected)");
1133
+ }
1134
+ }
1135
+ },
1136
+ onDestroy() {
1137
+ if (cleanup) {
1138
+ cleanup();
1139
+ cleanup = null;
1140
+ }
1141
+ }
1142
+ };
1143
+ }
1144
+
1020
1145
  // src/presets/index.ts
1021
- function full() {
1146
+ function full(config) {
1022
1147
  return [
1023
1148
  effects(),
1024
1149
  screensets({ autoDiscover: true }),
1025
- themes(),
1150
+ themes(config?.themes),
1026
1151
  layout(),
1027
1152
  routing(),
1028
1153
  navigation(),
1029
- i18n()
1154
+ i18n(),
1155
+ mock()
1030
1156
  ];
1031
1157
  }
1032
1158
  function minimal() {
@@ -1048,31 +1174,31 @@ var presets = {
1048
1174
 
1049
1175
  // src/createHAI3App.ts
1050
1176
  function createHAI3App(config) {
1051
- return createHAI3(config).useAll(full()).build();
1177
+ return createHAI3(config).useAll(full({ themes: config?.themes })).build();
1052
1178
  }
1053
1179
 
1054
1180
  // src/registries/index.ts
1055
- import { createScreensetRegistry, screensetRegistry as screensetRegistry2 } from "@hai3/screensets";
1181
+ import { createScreensetRegistry, screensetRegistry } from "@hai3/screensets";
1056
1182
 
1057
1183
  // src/index.ts
1058
- import { eventBus as eventBus6, createStore, getStore as getStore4, registerSlice as registerSlice2, hasSlice, createSlice as createSlice9 } from "@hai3/state";
1184
+ import { eventBus as eventBus7, createStore, getStore as getStore4, registerSlice as registerSlice2, hasSlice, createSlice as createSlice10 } from "@hai3/state";
1059
1185
  import {
1060
1186
  LayoutDomain,
1061
1187
  ScreensetCategory
1062
1188
  } from "@hai3/screensets";
1063
1189
 
1064
1190
  // src/effects/tenantEffects.ts
1065
- import { eventBus as eventBus5, getStore as getStore3 } from "@hai3/state";
1191
+ import { eventBus as eventBus6, getStore as getStore3 } from "@hai3/state";
1066
1192
  var TenantEvents = {
1067
1193
  Changed: "app/tenant/changed",
1068
1194
  Cleared: "app/tenant/cleared"
1069
1195
  };
1070
1196
  function initTenantEffects() {
1071
1197
  const store = getStore3();
1072
- const subChanged = eventBus5.on(TenantEvents.Changed, (payload) => {
1198
+ const subChanged = eventBus6.on(TenantEvents.Changed, (payload) => {
1073
1199
  store.dispatch(setTenant(payload.tenant));
1074
1200
  });
1075
- const subCleared = eventBus5.on(TenantEvents.Cleared, () => {
1201
+ const subCleared = eventBus6.on(TenantEvents.Cleared, () => {
1076
1202
  store.dispatch(clearTenant());
1077
1203
  });
1078
1204
  return () => {
@@ -1081,20 +1207,44 @@ function initTenantEffects() {
1081
1207
  };
1082
1208
  }
1083
1209
  function changeTenant(tenant) {
1084
- eventBus5.emit(TenantEvents.Changed, { tenant });
1210
+ eventBus6.emit(TenantEvents.Changed, { tenant });
1085
1211
  }
1086
1212
  function clearTenantAction() {
1087
- eventBus5.emit(TenantEvents.Cleared, {});
1213
+ eventBus6.emit(TenantEvents.Cleared, {});
1088
1214
  }
1089
1215
  function setTenantLoadingState(loading) {
1090
1216
  getStore3().dispatch(setTenantLoading(loading));
1091
1217
  }
1092
1218
 
1093
1219
  // src/index.ts
1094
- import { apiRegistry as apiRegistry3, BaseApiService, RestProtocol, SseProtocol, MockPlugin } from "@hai3/api";
1220
+ import {
1221
+ apiRegistry as apiRegistry3,
1222
+ BaseApiService,
1223
+ RestProtocol,
1224
+ SseProtocol,
1225
+ RestMockPlugin,
1226
+ SseMockPlugin,
1227
+ MockEventSource,
1228
+ ApiPluginBase,
1229
+ ApiPlugin,
1230
+ ApiProtocol,
1231
+ RestPlugin,
1232
+ RestPluginWithConfig,
1233
+ SsePlugin,
1234
+ SsePluginWithConfig,
1235
+ isShortCircuit,
1236
+ isRestShortCircuit,
1237
+ isSseShortCircuit,
1238
+ MOCK_PLUGIN,
1239
+ isMockPlugin as isMockPlugin2
1240
+ } from "@hai3/api";
1095
1241
  import { i18nRegistry as i18nRegistry2, I18nRegistryImpl, createI18nRegistry, Language as Language2, SUPPORTED_LANGUAGES, getLanguageMetadata, TextDirection, LanguageDisplayMode } from "@hai3/i18n";
1096
1242
  import { I18nRegistryImpl as I18nRegistryImpl2 } from "@hai3/i18n";
1097
1243
 
1244
+ // src/compat.ts
1245
+ import { screensetRegistry as screensetRegistry2 } from "@hai3/screensets";
1246
+ var ACCOUNTS_DOMAIN = "accounts";
1247
+
1098
1248
  // src/migration.ts
1099
1249
  var STATE_PATH_MAPPING = {
1100
1250
  // App state (moved to app slice)
@@ -1148,9 +1298,11 @@ function hasLegacyUicoreState(state) {
1148
1298
  function hasNewLayoutState(state) {
1149
1299
  return typeof state === "object" && state !== null && "layout" in state && typeof state.layout === "object";
1150
1300
  }
1151
- var legacySelectors = {};
1152
1301
  export {
1153
1302
  ACCOUNTS_DOMAIN,
1303
+ ApiPlugin,
1304
+ ApiPluginBase,
1305
+ ApiProtocol,
1154
1306
  BaseApiService,
1155
1307
  I18nRegistryImpl2 as I18nRegistry,
1156
1308
  I18nRegistryImpl,
@@ -1158,11 +1310,19 @@ export {
1158
1310
  Language2 as Language,
1159
1311
  LanguageDisplayMode,
1160
1312
  LayoutDomain,
1161
- MockPlugin,
1313
+ MOCK_PLUGIN,
1314
+ MockEventSource,
1315
+ MockEvents,
1316
+ RestMockPlugin,
1317
+ RestPlugin,
1318
+ RestPluginWithConfig,
1162
1319
  RestProtocol,
1163
1320
  STATE_PATH_MAPPING,
1164
1321
  SUPPORTED_LANGUAGES,
1165
1322
  ScreensetCategory,
1323
+ SseMockPlugin,
1324
+ SsePlugin,
1325
+ SsePluginWithConfig,
1166
1326
  SseProtocol,
1167
1327
  TENANT_SLICE_NAME,
1168
1328
  TenantEvents,
@@ -1182,12 +1342,11 @@ export {
1182
1342
  createLegacySelector,
1183
1343
  createRouteRegistry,
1184
1344
  createScreensetRegistry,
1185
- createSlice9 as createSlice,
1345
+ createSlice10 as createSlice,
1186
1346
  createStore,
1187
1347
  createThemeRegistry,
1188
1348
  effects,
1189
- eventBus6 as eventBus,
1190
- fetchCurrentUser,
1349
+ eventBus7 as eventBus,
1191
1350
  footerActions,
1192
1351
  footerSlice,
1193
1352
  full,
@@ -1203,17 +1362,23 @@ export {
1203
1362
  hideOverlay,
1204
1363
  i18n,
1205
1364
  i18nRegistry2 as i18nRegistry,
1365
+ initMockEffects,
1206
1366
  initTenantEffects,
1207
1367
  isDeprecationWarningsEnabled,
1368
+ isMockPlugin2 as isMockPlugin,
1369
+ isRestShortCircuit,
1370
+ isShortCircuit,
1371
+ isSseShortCircuit,
1208
1372
  layout,
1209
1373
  layoutDomainReducers,
1210
1374
  layoutReducer,
1211
- legacySelectors,
1212
1375
  menuActions,
1213
1376
  menuSlice,
1214
1377
  minimal,
1378
+ mock,
1379
+ mockActions,
1380
+ mockSlice,
1215
1381
  navigateTo,
1216
- navigateToScreen,
1217
1382
  navigation,
1218
1383
  openPopup,
1219
1384
  overlayActions,
@@ -1222,11 +1387,10 @@ export {
1222
1387
  popupSlice,
1223
1388
  presets,
1224
1389
  registerSlice2 as registerSlice,
1225
- routeRegistry,
1226
1390
  routing,
1227
1391
  screenActions,
1228
1392
  screenSlice,
1229
- screensetRegistry,
1393
+ screensetRegistry2 as screensetRegistry,
1230
1394
  screensets,
1231
1395
  setActiveScreen,
1232
1396
  setDeprecationWarnings,
@@ -1237,6 +1401,7 @@ export {
1237
1401
  setMenuConfig,
1238
1402
  setMenuItems,
1239
1403
  setMenuVisible,
1404
+ setMockEnabled,
1240
1405
  setOverlayVisible,
1241
1406
  setScreenLoading,
1242
1407
  setSidebarCollapsed,
@@ -1256,9 +1421,9 @@ export {
1256
1421
  tenantActions,
1257
1422
  tenantSlice_default as tenantReducer,
1258
1423
  tenantSlice,
1259
- themeRegistry,
1260
1424
  themes,
1261
1425
  toggleMenu,
1426
+ toggleMockMode,
1262
1427
  toggleSidebar
1263
1428
  };
1264
1429
  //# sourceMappingURL=index.js.map