@carlonicora/nextjs-jsonapi 1.52.0 → 1.53.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 (99) hide show
  1. package/dist/{AuthComponent-BkK4Sf3q.d.mts → AuthComponent-CK9aRRW2.d.mts} +1 -1
  2. package/dist/{AuthComponent-DCfP4o32.d.ts → AuthComponent-IqFWLNIU.d.ts} +1 -1
  3. package/dist/{BlockNoteEditor-KQPSJCYG.js → BlockNoteEditor-AROKR3J6.js} +14 -14
  4. package/dist/{BlockNoteEditor-KQPSJCYG.js.map → BlockNoteEditor-AROKR3J6.js.map} +1 -1
  5. package/dist/{BlockNoteEditor-WUVRCTQI.mjs → BlockNoteEditor-CNMSBGCL.mjs} +4 -4
  6. package/dist/ModulePathsInterface-49EWvbWy.d.mts +31 -0
  7. package/dist/ModulePathsInterface-wVS5Raa4.d.ts +31 -0
  8. package/dist/{auth.interface-C4kEZscm.d.ts → auth.interface-C1WjZ0fM.d.ts} +1 -1
  9. package/dist/{auth.interface-24ID4yhT.d.mts → auth.interface-fBFqIrw4.d.mts} +1 -1
  10. package/dist/billing/index.js +346 -346
  11. package/dist/billing/index.mjs +3 -3
  12. package/dist/{chunk-BUCV5VFT.mjs → chunk-FE26PIZK.mjs} +53 -2
  13. package/dist/chunk-FE26PIZK.mjs.map +1 -0
  14. package/dist/{chunk-BTLJZIDS.mjs → chunk-G5473JP3.mjs} +869 -40
  15. package/dist/chunk-G5473JP3.mjs.map +1 -0
  16. package/dist/{chunk-XNISXVQL.mjs → chunk-J2PYGXVD.mjs} +70 -1
  17. package/dist/chunk-J2PYGXVD.mjs.map +1 -0
  18. package/dist/{chunk-YKPIFJOB.js → chunk-PQIXFKHT.js} +1457 -628
  19. package/dist/chunk-PQIXFKHT.js.map +1 -0
  20. package/dist/{chunk-QIA5FOQB.js → chunk-QOLVON35.js} +71 -2
  21. package/dist/chunk-QOLVON35.js.map +1 -0
  22. package/dist/{chunk-V63TFESU.js → chunk-UJBUJALX.js} +53 -2
  23. package/dist/chunk-UJBUJALX.js.map +1 -0
  24. package/dist/client/index.d.mts +25 -7
  25. package/dist/client/index.d.ts +25 -7
  26. package/dist/client/index.js +10 -4
  27. package/dist/client/index.js.map +1 -1
  28. package/dist/client/index.mjs +9 -3
  29. package/dist/components/index.d.mts +52 -10
  30. package/dist/components/index.d.ts +52 -10
  31. package/dist/components/index.js +16 -4
  32. package/dist/components/index.js.map +1 -1
  33. package/dist/components/index.mjs +15 -3
  34. package/dist/{config-CPN6QZfo.d.ts → config-DZWAFB7H.d.ts} +1 -1
  35. package/dist/{config-DaxjKdIo.d.mts → config-ndRJIQsP.d.mts} +1 -1
  36. package/dist/{content.interface-DvPs_JbX.d.mts → content.interface-B5ySfiOE.d.mts} +1 -1
  37. package/dist/{content.interface-Czin-YRh.d.ts → content.interface-mmz0uMwm.d.ts} +1 -1
  38. package/dist/contexts/index.d.mts +2 -2
  39. package/dist/contexts/index.d.ts +2 -2
  40. package/dist/contexts/index.js +4 -4
  41. package/dist/contexts/index.mjs +3 -3
  42. package/dist/core/index.d.mts +15 -10
  43. package/dist/core/index.d.ts +15 -10
  44. package/dist/core/index.js +6 -2
  45. package/dist/core/index.js.map +1 -1
  46. package/dist/core/index.mjs +5 -1
  47. package/dist/index.d.mts +47 -10
  48. package/dist/index.d.ts +47 -10
  49. package/dist/index.js +17 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/index.mjs +16 -2
  52. package/dist/{notification.interface-DEW8hR8g.d.ts → notification.interface-COKHDQeE.d.ts} +1 -1
  53. package/dist/{notification.interface-DKR5WGKH.d.mts → notification.interface-DG7cq9oG.d.mts} +1 -1
  54. package/dist/{s3.service-BHjcTA0t.d.mts → s3.service-BoRPFx82.d.mts} +4 -4
  55. package/dist/{s3.service-C_K1VHyx.d.ts → s3.service-ppn9iGJU.d.ts} +4 -4
  56. package/dist/server/index.d.mts +4 -4
  57. package/dist/server/index.d.ts +4 -4
  58. package/dist/server/index.js +3 -3
  59. package/dist/server/index.mjs +1 -1
  60. package/dist/useRbacState-DhuYYr0S.d.mts +77 -0
  61. package/dist/useRbacState-NnzNL2ED.d.ts +77 -0
  62. package/dist/{useSocket-BW6haECW.d.mts → useSocket-CtfuR5wD.d.mts} +1 -1
  63. package/dist/{useSocket-C9FmYuRM.d.ts → useSocket-bsV-K4qR.d.ts} +1 -1
  64. package/package.json +1 -1
  65. package/src/client/index.ts +4 -0
  66. package/src/components/containers/RoundPageContainer.tsx +1 -1
  67. package/src/components/containers/RoundPageContainerTitle.tsx +1 -1
  68. package/src/components/index.ts +6 -0
  69. package/src/core/index.ts +1 -0
  70. package/src/core/registry/ModuleRegistry.ts +3 -0
  71. package/src/features/rbac/components/RbacContainer.tsx +82 -0
  72. package/src/features/rbac/components/RbacFeatureSection.tsx +66 -0
  73. package/src/features/rbac/components/RbacModuleTable.tsx +121 -0
  74. package/src/features/rbac/components/RbacPermissionCell.tsx +97 -0
  75. package/src/features/rbac/components/RbacPermissionPicker.tsx +179 -0
  76. package/src/features/rbac/components/RbacToolbar.tsx +40 -0
  77. package/src/features/rbac/data/ModulePaths.ts +25 -0
  78. package/src/features/rbac/data/ModulePathsInterface.ts +6 -0
  79. package/src/features/rbac/data/PermissionMapping.ts +43 -0
  80. package/src/features/rbac/data/PermissionMappingInterface.ts +12 -0
  81. package/src/features/rbac/data/RbacService.ts +47 -0
  82. package/src/features/rbac/data/RbacTypes.ts +15 -0
  83. package/src/features/rbac/data/index.ts +6 -0
  84. package/src/features/rbac/hooks/useRbacState.test.ts +178 -0
  85. package/src/features/rbac/hooks/useRbacState.ts +319 -0
  86. package/src/features/rbac/index.ts +19 -0
  87. package/src/features/rbac/rbac.module.ts +19 -0
  88. package/src/features/rbac/utils/RbacMigrationGenerator.test.ts +124 -0
  89. package/src/features/rbac/utils/RbacMigrationGenerator.ts +184 -0
  90. package/src/index.ts +4 -0
  91. package/dist/chunk-BTLJZIDS.mjs.map +0 -1
  92. package/dist/chunk-BUCV5VFT.mjs.map +0 -1
  93. package/dist/chunk-QIA5FOQB.js.map +0 -1
  94. package/dist/chunk-V63TFESU.js.map +0 -1
  95. package/dist/chunk-XNISXVQL.mjs.map +0 -1
  96. package/dist/chunk-YKPIFJOB.js.map +0 -1
  97. package/dist/useDataListRetriever-BqJSFBck.d.mts +0 -33
  98. package/dist/useDataListRetriever-BqJSFBck.d.ts +0 -33
  99. /package/dist/{BlockNoteEditor-WUVRCTQI.mjs.map → BlockNoteEditor-CNMSBGCL.mjs.map} +0 -0
@@ -1,4 +1,7 @@
1
1
  import {
2
+ ACTION_TYPES,
3
+ COMPANY_ADMINISTRATOR_ROLE_ID,
4
+ RbacService,
2
5
  getApiUrl,
3
6
  getAppUrl,
4
7
  getI18nLink,
@@ -18,7 +21,7 @@ import {
18
21
  useI18nLocale,
19
22
  useI18nRouter,
20
23
  useI18nTranslations
21
- } from "./chunk-BUCV5VFT.mjs";
24
+ } from "./chunk-FE26PIZK.mjs";
22
25
  import {
23
26
  AVAILABLE_OAUTH_SCOPES,
24
27
  AuthService,
@@ -49,7 +52,7 @@ import {
49
52
  showToast,
50
53
  useComposedRefs,
51
54
  useIsMobile
52
- } from "./chunk-XNISXVQL.mjs";
55
+ } from "./chunk-J2PYGXVD.mjs";
53
56
  import {
54
57
  JsonApiContext
55
58
  } from "./chunk-VOXD3ZLY.mjs";
@@ -11873,7 +11876,7 @@ __name(AllowedUsersDetails, "AllowedUsersDetails");
11873
11876
  import dynamic from "next/dynamic";
11874
11877
  import React17 from "react";
11875
11878
  import { jsx as jsx131 } from "react/jsx-runtime";
11876
- var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-WUVRCTQI.mjs"), {
11879
+ var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-CNMSBGCL.mjs"), {
11877
11880
  ssr: false
11878
11881
  });
11879
11882
  var BlockNoteEditorContainer = React17.memo(/* @__PURE__ */ __name(function EditorContainer(props) {
@@ -13014,6 +13017,377 @@ function useOAuthConsent(params) {
13014
13017
  }
13015
13018
  __name(useOAuthConsent, "useOAuthConsent");
13016
13019
 
13020
+ // src/features/rbac/hooks/useRbacState.ts
13021
+ import { useCallback as useCallback22, useMemo as useMemo21, useReducer } from "react";
13022
+ function createInitialState() {
13023
+ return {
13024
+ original: null,
13025
+ featureIsCore: /* @__PURE__ */ new Map(),
13026
+ modulePermissions: /* @__PURE__ */ new Map(),
13027
+ rolePermissions: /* @__PURE__ */ new Map()
13028
+ };
13029
+ }
13030
+ __name(createInitialState, "createInitialState");
13031
+ function findModule(features, moduleId) {
13032
+ for (const feature of features) {
13033
+ for (const mod of feature.modules) {
13034
+ if (mod.id === moduleId) return mod;
13035
+ }
13036
+ }
13037
+ return void 0;
13038
+ }
13039
+ __name(findModule, "findModule");
13040
+ function findPermissionMapping(mappings, roleId, moduleId) {
13041
+ return mappings.find((pm) => pm.roleId === roleId && pm.moduleId === moduleId);
13042
+ }
13043
+ __name(findPermissionMapping, "findPermissionMapping");
13044
+ function rbacReducer(state, action) {
13045
+ switch (action.type) {
13046
+ case "INIT": {
13047
+ return {
13048
+ ...createInitialState(),
13049
+ original: action.payload
13050
+ };
13051
+ }
13052
+ case "SET_FEATURE_IS_CORE": {
13053
+ const newMap = new Map(state.featureIsCore);
13054
+ const originalFeature = state.original?.features.find((f) => f.id === action.featureId);
13055
+ if (originalFeature && originalFeature.isCore === action.isCore) {
13056
+ newMap.delete(action.featureId);
13057
+ } else {
13058
+ newMap.set(action.featureId, action.isCore);
13059
+ }
13060
+ return { ...state, featureIsCore: newMap };
13061
+ }
13062
+ case "SET_MODULE_DEFAULT_PERMISSION": {
13063
+ const newMap = new Map(state.modulePermissions);
13064
+ const originalModule = state.original ? findModule(state.original.features, action.moduleId) : void 0;
13065
+ const current = newMap.get(action.moduleId) ?? { ...originalModule?.permissions };
13066
+ const updated = { ...current, [action.actionType]: action.value };
13067
+ newMap.set(action.moduleId, updated);
13068
+ return { ...state, modulePermissions: newMap };
13069
+ }
13070
+ case "SET_ROLE_PERMISSION": {
13071
+ const key = `${action.roleId}:${action.moduleId}`;
13072
+ const newMap = new Map(state.rolePermissions);
13073
+ const existing = newMap.get(key);
13074
+ if (existing === null) {
13075
+ newMap.set(key, { [action.actionType]: action.value });
13076
+ } else {
13077
+ const originalMapping = state.original ? findPermissionMapping(state.original.permissionMappings, action.roleId, action.moduleId) : void 0;
13078
+ const current = existing ?? (originalMapping ? { ...originalMapping.permissions } : {});
13079
+ newMap.set(key, { ...current, [action.actionType]: action.value });
13080
+ }
13081
+ return { ...state, rolePermissions: newMap };
13082
+ }
13083
+ case "CLEAR_ROLE_PERMISSION": {
13084
+ const key = `${action.roleId}:${action.moduleId}`;
13085
+ const newMap = new Map(state.rolePermissions);
13086
+ const existing = newMap.get(key);
13087
+ if (existing === null) return state;
13088
+ const originalMapping = state.original ? findPermissionMapping(state.original.permissionMappings, action.roleId, action.moduleId) : void 0;
13089
+ const current = existing ?? (originalMapping ? { ...originalMapping.permissions } : {});
13090
+ const updated = { ...current };
13091
+ delete updated[action.actionType];
13092
+ const hasAnyPermission = ACTION_TYPES.some((at) => updated[at] !== void 0);
13093
+ newMap.set(key, hasAnyPermission ? updated : null);
13094
+ return { ...state, rolePermissions: newMap };
13095
+ }
13096
+ case "CLEAR_ALL_ROLE_PERMISSIONS": {
13097
+ const key = `${action.roleId}:${action.moduleId}`;
13098
+ const newMap = new Map(state.rolePermissions);
13099
+ newMap.set(key, null);
13100
+ return { ...state, rolePermissions: newMap };
13101
+ }
13102
+ case "RESET":
13103
+ return {
13104
+ ...createInitialState(),
13105
+ original: state.original
13106
+ };
13107
+ default:
13108
+ return state;
13109
+ }
13110
+ }
13111
+ __name(rbacReducer, "rbacReducer");
13112
+ function useRbacState() {
13113
+ const [state, dispatch] = useReducer(rbacReducer, void 0, createInitialState);
13114
+ const init = useCallback22(
13115
+ (features, roles, permissionMappings, modulePaths) => {
13116
+ const moduleRelationshipPaths = /* @__PURE__ */ new Map();
13117
+ for (const mp of modulePaths) {
13118
+ moduleRelationshipPaths.set(mp.moduleId, mp.paths);
13119
+ }
13120
+ dispatch({ type: "INIT", payload: { features, roles, permissionMappings, moduleRelationshipPaths } });
13121
+ },
13122
+ []
13123
+ );
13124
+ const setFeatureIsCore = useCallback22((featureId, isCore) => {
13125
+ dispatch({ type: "SET_FEATURE_IS_CORE", featureId, isCore });
13126
+ }, []);
13127
+ const setModuleDefaultPermission = useCallback22((moduleId, actionType, value) => {
13128
+ dispatch({ type: "SET_MODULE_DEFAULT_PERMISSION", moduleId, actionType, value });
13129
+ }, []);
13130
+ const setRolePermission = useCallback22(
13131
+ (roleId, moduleId, actionType, value) => {
13132
+ dispatch({ type: "SET_ROLE_PERMISSION", roleId, moduleId, actionType, value });
13133
+ },
13134
+ []
13135
+ );
13136
+ const clearRolePermission = useCallback22((roleId, moduleId, actionType) => {
13137
+ dispatch({ type: "CLEAR_ROLE_PERMISSION", roleId, moduleId, actionType });
13138
+ }, []);
13139
+ const clearAllRolePermissions = useCallback22((roleId, moduleId) => {
13140
+ dispatch({ type: "CLEAR_ALL_ROLE_PERMISSIONS", roleId, moduleId });
13141
+ }, []);
13142
+ const resetModulePermissions = useCallback22((moduleId, roles) => {
13143
+ for (const actionType of ACTION_TYPES) {
13144
+ dispatch({ type: "SET_MODULE_DEFAULT_PERMISSION", moduleId, actionType, value: true });
13145
+ }
13146
+ for (const role of roles) {
13147
+ dispatch({ type: "CLEAR_ALL_ROLE_PERMISSIONS", roleId: role.id, moduleId });
13148
+ }
13149
+ }, []);
13150
+ const reset = useCallback22(() => {
13151
+ dispatch({ type: "RESET" });
13152
+ }, []);
13153
+ const getFeatureIsCore = useCallback22(
13154
+ (featureId) => {
13155
+ if (state.featureIsCore.has(featureId)) return state.featureIsCore.get(featureId);
13156
+ const feature = state.original?.features.find((f) => f.id === featureId);
13157
+ return feature?.isCore ?? false;
13158
+ },
13159
+ [state.featureIsCore, state.original]
13160
+ );
13161
+ const getModuleDefaultPermission = useCallback22(
13162
+ (moduleId, actionType) => {
13163
+ const edited = state.modulePermissions.get(moduleId);
13164
+ if (edited && edited[actionType] !== void 0) return edited[actionType];
13165
+ if (!state.original) return void 0;
13166
+ const mod = findModule(state.original.features, moduleId);
13167
+ return mod?.permissions[actionType];
13168
+ },
13169
+ [state.modulePermissions, state.original]
13170
+ );
13171
+ const getRolePermission = useCallback22(
13172
+ (roleId, moduleId, actionType) => {
13173
+ const key = `${roleId}:${moduleId}`;
13174
+ if (state.rolePermissions.has(key)) {
13175
+ const perms = state.rolePermissions.get(key);
13176
+ if (perms === null || perms === void 0) return null;
13177
+ return perms[actionType] ?? null;
13178
+ }
13179
+ if (!state.original) return void 0;
13180
+ const mapping = findPermissionMapping(state.original.permissionMappings, roleId, moduleId);
13181
+ if (!mapping) return void 0;
13182
+ return mapping.permissions[actionType] ?? null;
13183
+ },
13184
+ [state.rolePermissions, state.original]
13185
+ );
13186
+ const isDirty = useMemo21(() => {
13187
+ return state.featureIsCore.size > 0 || state.modulePermissions.size > 0 || state.rolePermissions.size > 0;
13188
+ }, [state.featureIsCore, state.modulePermissions, state.rolePermissions]);
13189
+ const getEffectiveConfiguration = useCallback22(() => {
13190
+ if (!state.original) return null;
13191
+ const features = state.original.features.map((f) => ({
13192
+ id: f.id,
13193
+ name: f.name,
13194
+ isCore: state.featureIsCore.has(f.id) ? state.featureIsCore.get(f.id) : f.isCore,
13195
+ modules: f.modules.map((m) => {
13196
+ const editedPerms = state.modulePermissions.get(m.id);
13197
+ return {
13198
+ id: m.id,
13199
+ name: m.name,
13200
+ permissions: editedPerms ?? m.permissions
13201
+ };
13202
+ })
13203
+ }));
13204
+ const rolePermissionsMap = /* @__PURE__ */ new Map();
13205
+ for (const pm of state.original.permissionMappings) {
13206
+ rolePermissionsMap.set(`${pm.roleId}:${pm.moduleId}`, { ...pm.permissions });
13207
+ }
13208
+ for (const [key, perms] of state.rolePermissions) {
13209
+ if (perms === null) {
13210
+ rolePermissionsMap.delete(key);
13211
+ } else {
13212
+ rolePermissionsMap.set(key, perms);
13213
+ }
13214
+ }
13215
+ return {
13216
+ features,
13217
+ roles: state.original.roles,
13218
+ rolePermissionsMap
13219
+ };
13220
+ }, [state]);
13221
+ const getModuleRelationshipPaths = useCallback22(
13222
+ (moduleId) => {
13223
+ return state.original?.moduleRelationshipPaths.get(moduleId) ?? [];
13224
+ },
13225
+ [state.original]
13226
+ );
13227
+ return {
13228
+ original: state.original,
13229
+ isDirty,
13230
+ init,
13231
+ setFeatureIsCore,
13232
+ setModuleDefaultPermission,
13233
+ setRolePermission,
13234
+ clearRolePermission,
13235
+ clearAllRolePermissions,
13236
+ resetModulePermissions,
13237
+ reset,
13238
+ getFeatureIsCore,
13239
+ getModuleDefaultPermission,
13240
+ getRolePermission,
13241
+ getEffectiveConfiguration,
13242
+ getModuleRelationshipPaths
13243
+ };
13244
+ }
13245
+ __name(useRbacState, "useRbacState");
13246
+
13247
+ // src/features/rbac/utils/RbacMigrationGenerator.ts
13248
+ var ACTION_ENUM_MAP = {
13249
+ read: "Action.Read",
13250
+ create: "Action.Create",
13251
+ update: "Action.Update",
13252
+ delete: "Action.Delete"
13253
+ };
13254
+ function formatPermissionValue(value) {
13255
+ if (value === true) return "true";
13256
+ if (value === false) return "false";
13257
+ return `"${value}"`;
13258
+ }
13259
+ __name(formatPermissionValue, "formatPermissionValue");
13260
+ function formatPermissionsFromMap(perms) {
13261
+ const entries = [];
13262
+ for (const actionType of ACTION_TYPES) {
13263
+ const value = perms[actionType];
13264
+ if (value !== void 0) {
13265
+ entries.push(`{ type: ${ACTION_ENUM_MAP[actionType]}, value: ${formatPermissionValue(value)} }`);
13266
+ }
13267
+ }
13268
+ if (entries.length === 0) return "[]";
13269
+ if (entries.length === 1) return `[${entries[0]}]`;
13270
+ return `[
13271
+ ${entries.join(",\n ")},
13272
+ ]`;
13273
+ }
13274
+ __name(formatPermissionsFromMap, "formatPermissionsFromMap");
13275
+ function generateMigrationFile(params) {
13276
+ const { features, roles, rolePermissionsMap } = params;
13277
+ const lines = [];
13278
+ lines.push(`/**`);
13279
+ lines.push(` * RBAC Migration - Generated on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`);
13280
+ lines.push(` * Contains features, modules, roles, and permission mappings.`);
13281
+ lines.push(` */`);
13282
+ lines.push(``);
13283
+ lines.push(`import { Action } from "src/common/enums/action";`);
13284
+ lines.push(`import { MigrationInterface } from "src/core/migrator/interfaces/migration.interface";`);
13285
+ lines.push(
13286
+ `import { featureQuery, moduleQuery, roleQuery, permissionQuery } from "src/neo4j.migrations/queries/migration.queries";`
13287
+ );
13288
+ lines.push(``);
13289
+ lines.push(`export const migration: MigrationInterface[] = [`);
13290
+ lines.push(` /* ************************************ */`);
13291
+ lines.push(` /* FEATURES */`);
13292
+ lines.push(` /* ************************************ */`);
13293
+ for (const feature of features) {
13294
+ lines.push(` {`);
13295
+ lines.push(` query: featureQuery,`);
13296
+ lines.push(` queryParams: {`);
13297
+ lines.push(` featureId: "${feature.id}",`);
13298
+ lines.push(` featureName: "${feature.name}",`);
13299
+ lines.push(` isCore: ${feature.isCore},`);
13300
+ lines.push(` },`);
13301
+ lines.push(` },`);
13302
+ }
13303
+ for (const feature of features) {
13304
+ if (feature.modules.length === 0) continue;
13305
+ lines.push(` /* ************************************ */`);
13306
+ lines.push(` /* ${feature.name.toUpperCase().padEnd(37)} */`);
13307
+ lines.push(` /* ************************************ */`);
13308
+ for (const mod of feature.modules) {
13309
+ lines.push(` {`);
13310
+ lines.push(` query: moduleQuery,`);
13311
+ lines.push(` queryParams: {`);
13312
+ lines.push(` moduleName: "${mod.name}",`);
13313
+ lines.push(` moduleId: "${mod.id}",`);
13314
+ lines.push(` featureId: "${feature.id}",`);
13315
+ lines.push(` permissions: JSON.stringify(${formatPermissionsFromMap(mod.permissions)}),`);
13316
+ lines.push(` },`);
13317
+ lines.push(` },`);
13318
+ }
13319
+ }
13320
+ lines.push(` /* ************************************ */`);
13321
+ lines.push(` /* ROLES */`);
13322
+ lines.push(` /* ************************************ */`);
13323
+ for (const role of roles) {
13324
+ lines.push(` {`);
13325
+ lines.push(` query: roleQuery,`);
13326
+ lines.push(` queryParams: {`);
13327
+ lines.push(` roleId: "${role.id}",`);
13328
+ lines.push(` roleName: "${role.name}",`);
13329
+ lines.push(` isSelectable: ${role.isSelectable},`);
13330
+ lines.push(` },`);
13331
+ lines.push(` },`);
13332
+ }
13333
+ lines.push(` /* ************************************ */`);
13334
+ lines.push(` /* PERMISSIONS */`);
13335
+ lines.push(` /* ************************************ */`);
13336
+ const allModuleIds = [];
13337
+ for (const feature of features) {
13338
+ for (const mod of feature.modules) {
13339
+ allModuleIds.push(mod.id);
13340
+ }
13341
+ }
13342
+ const allTruePermissions = { read: true, create: true, update: true, delete: true };
13343
+ const permsByRole = /* @__PURE__ */ new Map();
13344
+ permsByRole.set(
13345
+ COMPANY_ADMINISTRATOR_ROLE_ID,
13346
+ allModuleIds.map((moduleId) => ({ moduleId, permissions: allTruePermissions }))
13347
+ );
13348
+ for (const [key, perms] of rolePermissionsMap) {
13349
+ const [roleId, moduleId] = key.split(":");
13350
+ if (roleId === COMPANY_ADMINISTRATOR_ROLE_ID) continue;
13351
+ if (!permsByRole.has(roleId)) permsByRole.set(roleId, []);
13352
+ permsByRole.get(roleId).push({ moduleId, permissions: perms });
13353
+ }
13354
+ for (const [roleId, moduleMappings] of permsByRole) {
13355
+ const role = roles.find((r) => r.id === roleId);
13356
+ if (role) {
13357
+ lines.push(` // ${role.name}`);
13358
+ }
13359
+ for (const mapping of moduleMappings) {
13360
+ lines.push(` {`);
13361
+ lines.push(` query: permissionQuery,`);
13362
+ lines.push(` queryParams: {`);
13363
+ lines.push(` roleId: "${roleId}",`);
13364
+ lines.push(` moduleId: "${mapping.moduleId}",`);
13365
+ lines.push(` permissions: JSON.stringify(${formatPermissionsFromMap(mapping.permissions)}),`);
13366
+ lines.push(` },`);
13367
+ lines.push(` },`);
13368
+ }
13369
+ }
13370
+ lines.push(`];`);
13371
+ lines.push(``);
13372
+ return lines.join("\n");
13373
+ }
13374
+ __name(generateMigrationFile, "generateMigrationFile");
13375
+ function downloadMigrationFile(content) {
13376
+ const now = /* @__PURE__ */ new Date();
13377
+ const dateStr = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}`;
13378
+ const filename = `${dateStr}_001.ts`;
13379
+ const blob = new Blob([content], { type: "text/plain" });
13380
+ const url = URL.createObjectURL(blob);
13381
+ const a = document.createElement("a");
13382
+ a.href = url;
13383
+ a.download = filename;
13384
+ document.body.appendChild(a);
13385
+ a.click();
13386
+ document.body.removeChild(a);
13387
+ URL.revokeObjectURL(url);
13388
+ }
13389
+ __name(downloadMigrationFile, "downloadMigrationFile");
13390
+
13017
13391
  // src/client/index.ts
13018
13392
  registerTableGenerator("roles", useRoleTableStructure);
13019
13393
  registerTableGenerator("users", useUserTableStructure);
@@ -13022,12 +13396,12 @@ registerTableGenerator("companies", useCompanyTableStructure);
13022
13396
  // src/components/tables/ContentListTable.tsx
13023
13397
  import { flexRender, getCoreRowModel, getExpandedRowModel, useReactTable } from "@tanstack/react-table";
13024
13398
  import { ChevronLeft, ChevronRight } from "lucide-react";
13025
- import { memo, useMemo as useMemo21, useState as useState48 } from "react";
13399
+ import { memo, useMemo as useMemo22, useState as useState48 } from "react";
13026
13400
 
13027
13401
  // src/components/tables/ContentTableSearch.tsx
13028
13402
  import { RefreshCw, Search, X as X3 } from "lucide-react";
13029
13403
  import { useTranslations as useTranslations47 } from "next-intl";
13030
- import { useCallback as useCallback22, useEffect as useEffect41, useRef as useRef21, useState as useState47 } from "react";
13404
+ import { useCallback as useCallback23, useEffect as useEffect41, useRef as useRef21, useState as useState47 } from "react";
13031
13405
  import { jsx as jsx143, jsxs as jsxs83 } from "react/jsx-runtime";
13032
13406
  function ContentTableSearch({ data }) {
13033
13407
  const t = useTranslations47();
@@ -13037,7 +13411,7 @@ function ContentTableSearch({ data }) {
13037
13411
  const [isFocused, setIsFocused] = useState47(false);
13038
13412
  const [isSearching, setIsSearching] = useState47(false);
13039
13413
  const isExpanded = isFocused || searchTerm.length > 0;
13040
- const search = useCallback22(
13414
+ const search = useCallback23(
13041
13415
  async (searchedTerm) => {
13042
13416
  try {
13043
13417
  if (searchedTerm === searchTermRef.current) return;
@@ -13130,7 +13504,7 @@ var ContentListTable = memo(/* @__PURE__ */ __name(function ContentListTable2(pr
13130
13504
  dataRetriever: data,
13131
13505
  context: props.context
13132
13506
  });
13133
- const columnVisibility = useMemo21(
13507
+ const columnVisibility = useMemo22(
13134
13508
  () => fields.reduce(
13135
13509
  (acc, columnId) => {
13136
13510
  acc[columnId] = true;
@@ -13211,7 +13585,7 @@ var ContentListTable = memo(/* @__PURE__ */ __name(function ContentListTable2(pr
13211
13585
  import Image9 from "next/image";
13212
13586
 
13213
13587
  // src/features/auth/contexts/AuthContext.tsx
13214
- import { createContext as createContext16, useContext as useContext17, useMemo as useMemo22, useState as useState50 } from "react";
13588
+ import { createContext as createContext16, useContext as useContext17, useMemo as useMemo23, useState as useState50 } from "react";
13215
13589
 
13216
13590
  // src/features/auth/components/forms/Register.tsx
13217
13591
  import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
@@ -13570,7 +13944,7 @@ var AuthContextProvider = /* @__PURE__ */ __name(({
13570
13944
  const [componentType, setComponentType] = useState50(initialComponentType);
13571
13945
  const [params, setParams] = useState50(initialParams);
13572
13946
  const [pendingTwoFactor, setPendingTwoFactor] = useState50();
13573
- const activeComponent = useMemo22(() => {
13947
+ const activeComponent = useMemo23(() => {
13574
13948
  if (componentType === void 0) return null;
13575
13949
  switch (componentType) {
13576
13950
  case 0 /* Login */:
@@ -13631,7 +14005,7 @@ __name(InnerAuthContainer, "InnerAuthContainer");
13631
14005
  // src/features/auth/components/two-factor/TwoFactorSettings.tsx
13632
14006
  import { ShieldAlert, ShieldCheck } from "lucide-react";
13633
14007
  import { useTranslations as useTranslations56 } from "next-intl";
13634
- import { useCallback as useCallback23, useEffect as useEffect44, useState as useState58 } from "react";
14008
+ import { useCallback as useCallback24, useEffect as useEffect44, useState as useState58 } from "react";
13635
14009
  import { v4 as v47 } from "uuid";
13636
14010
 
13637
14011
  // src/features/auth/components/two-factor/BackupCodesDialog.tsx
@@ -14235,7 +14609,7 @@ function TwoFactorSettings() {
14235
14609
  const [isLoading, setIsLoading] = useState58(true);
14236
14610
  const [isEnabling, setIsEnabling] = useState58(false);
14237
14611
  const [passkeyDialogOpen, setPasskeyDialogOpen] = useState58(false);
14238
- const loadStatus = useCallback23(async () => {
14612
+ const loadStatus = useCallback24(async () => {
14239
14613
  try {
14240
14614
  const [statusData, authenticatorsList, passkeysList] = await Promise.all([
14241
14615
  TwoFactorService.getStatus(),
@@ -15365,7 +15739,7 @@ __name(NotificationsListContainer, "NotificationsListContainer");
15365
15739
  // src/features/notification/components/modals/NotificationModal.tsx
15366
15740
  import { BellIcon } from "lucide-react";
15367
15741
  import { useTranslations as useTranslations70 } from "next-intl";
15368
- import { Fragment as Fragment35, useCallback as useCallback24, useEffect as useEffect52, useMemo as useMemo23, useRef as useRef23, useState as useState67 } from "react";
15742
+ import { Fragment as Fragment35, useCallback as useCallback25, useEffect as useEffect52, useMemo as useMemo24, useRef as useRef23, useState as useState67 } from "react";
15369
15743
  import { jsx as jsx174, jsxs as jsxs107 } from "react/jsx-runtime";
15370
15744
  function NotificationModalContent({ isOpen, setIsOpen }) {
15371
15745
  const _instanceId = useRef23(Math.random().toString(36).substr(2, 9));
@@ -15395,7 +15769,7 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
15395
15769
  resetTime: 0,
15396
15770
  isOpen: false
15397
15771
  });
15398
- const checkCircuitBreaker = useCallback24(() => {
15772
+ const checkCircuitBreaker = useCallback25(() => {
15399
15773
  const now = Date.now();
15400
15774
  const breaker = circuitBreakerRef.current;
15401
15775
  if (now > breaker.resetTime) {
@@ -15410,7 +15784,7 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
15410
15784
  }
15411
15785
  return !breaker.isOpen;
15412
15786
  }, []);
15413
- const { unreadCount, unreadIds } = useMemo23(() => {
15787
+ const { unreadCount, unreadIds } = useMemo24(() => {
15414
15788
  const unreadNotifications2 = notifications.filter((notif) => !notif.isRead);
15415
15789
  return {
15416
15790
  unreadCount: unreadNotifications2.length,
@@ -15424,7 +15798,7 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
15424
15798
  if (lastLoaded === 0) loadNotifications();
15425
15799
  }, [lastLoaded, loadNotifications]);
15426
15800
  const processSocketNotificationsRef = useRef23(null);
15427
- const processSocketNotifications = useCallback24(() => {
15801
+ const processSocketNotifications = useCallback25(() => {
15428
15802
  if (socketNotifications.length === 0) {
15429
15803
  return;
15430
15804
  }
@@ -15584,7 +15958,7 @@ __name(ReferralCodeCapture, "ReferralCodeCapture");
15584
15958
 
15585
15959
  // src/features/referral/components/ReferralWidget.tsx
15586
15960
  import { Copy as Copy2, Loader2 as Loader25, Mail, Users } from "lucide-react";
15587
- import { useCallback as useCallback25, useRef as useRef24, useState as useState70 } from "react";
15961
+ import { useCallback as useCallback26, useRef as useRef24, useState as useState70 } from "react";
15588
15962
 
15589
15963
  // src/features/referral/hooks/useReferralInvite.ts
15590
15964
  import { useState as useState68 } from "react";
@@ -15697,7 +16071,7 @@ function ReferralWidget({
15697
16071
  if (!isReferralEnabled()) {
15698
16072
  return null;
15699
16073
  }
15700
- const handleCopyLink = useCallback25(async () => {
16074
+ const handleCopyLink = useCallback26(async () => {
15701
16075
  if (!referralUrl) return;
15702
16076
  const success = await copyToClipboard(referralUrl);
15703
16077
  if (success) {
@@ -15709,7 +16083,7 @@ function ReferralWidget({
15709
16083
  showError(t.copyError);
15710
16084
  }
15711
16085
  }, [referralUrl, t.copiedMessage, t.copyError, onLinkCopied]);
15712
- const handleSendInvite = useCallback25(async () => {
16086
+ const handleSendInvite = useCallback26(async () => {
15713
16087
  if (!email || !email.includes("@")) {
15714
16088
  showError(t.invalidEmail);
15715
16089
  return;
@@ -15725,7 +16099,7 @@ function ReferralWidget({
15725
16099
  onInviteError?.(error2);
15726
16100
  }
15727
16101
  }, [email, sendInvite, t.inviteSent, t.inviteError, t.invalidEmail, onInviteSent, onInviteError]);
15728
- const handleEmailKeyDown = useCallback25(
16102
+ const handleEmailKeyDown = useCallback26(
15729
16103
  (e) => {
15730
16104
  if (e.key === "Enter" && !sending) {
15731
16105
  e.preventDefault();
@@ -15977,7 +16351,7 @@ __name(RemoveUserFromRole, "RemoveUserFromRole");
15977
16351
  // src/features/role/components/forms/UserRoleAdd.tsx
15978
16352
  import { PlusCircle as PlusCircle2 } from "lucide-react";
15979
16353
  import { useTranslations as useTranslations74 } from "next-intl";
15980
- import { useCallback as useCallback26, useEffect as useEffect56, useRef as useRef25, useState as useState72 } from "react";
16354
+ import { useCallback as useCallback27, useEffect as useEffect56, useRef as useRef25, useState as useState72 } from "react";
15981
16355
  import { Fragment as Fragment39, jsx as jsx182, jsxs as jsxs113 } from "react/jsx-runtime";
15982
16356
  function UserRoleAdd({ user, refresh }) {
15983
16357
  const [open, setOpen] = useState72(false);
@@ -16007,7 +16381,7 @@ function UserRoleAdd({ user, refresh }) {
16007
16381
  );
16008
16382
  refresh();
16009
16383
  }, "addUserToRole");
16010
- const searchRoles = useCallback26(
16384
+ const searchRoles = useCallback27(
16011
16385
  async (term) => {
16012
16386
  setRoles(
16013
16387
  await RoleService.findAllRolesUserNotIn({
@@ -16117,7 +16491,7 @@ function UserRolesList({ user }) {
16117
16491
  __name(UserRolesList, "UserRolesList");
16118
16492
 
16119
16493
  // src/features/oauth/components/OAuthRedirectUriInput.tsx
16120
- import { useCallback as useCallback27 } from "react";
16494
+ import { useCallback as useCallback28 } from "react";
16121
16495
  import { Plus, Trash2 as Trash23 } from "lucide-react";
16122
16496
  import { jsx as jsx185, jsxs as jsxs114 } from "react/jsx-runtime";
16123
16497
  function isValidRedirectUri(uri) {
@@ -16147,17 +16521,17 @@ function OAuthRedirectUriInput({
16147
16521
  disabled = false,
16148
16522
  label = "Redirect URIs"
16149
16523
  }) {
16150
- const handleAdd = useCallback27(() => {
16524
+ const handleAdd = useCallback28(() => {
16151
16525
  onChange([...value, ""]);
16152
16526
  }, [value, onChange]);
16153
- const handleRemove = useCallback27(
16527
+ const handleRemove = useCallback28(
16154
16528
  (index) => {
16155
16529
  const newUris = value.filter((_, i) => i !== index);
16156
16530
  onChange(newUris.length > 0 ? newUris : [""]);
16157
16531
  },
16158
16532
  [value, onChange]
16159
16533
  );
16160
- const handleChange = useCallback27(
16534
+ const handleChange = useCallback28(
16161
16535
  (index, newValue) => {
16162
16536
  const newUris = [...value];
16163
16537
  newUris[index] = newValue;
@@ -16211,7 +16585,7 @@ function OAuthRedirectUriInput({
16211
16585
  __name(OAuthRedirectUriInput, "OAuthRedirectUriInput");
16212
16586
 
16213
16587
  // src/features/oauth/components/OAuthScopeSelector.tsx
16214
- import { useCallback as useCallback28 } from "react";
16588
+ import { useCallback as useCallback29 } from "react";
16215
16589
  import { jsx as jsx186, jsxs as jsxs115 } from "react/jsx-runtime";
16216
16590
  function OAuthScopeSelector({
16217
16591
  value,
@@ -16221,7 +16595,7 @@ function OAuthScopeSelector({
16221
16595
  error,
16222
16596
  label = "Allowed Scopes"
16223
16597
  }) {
16224
- const handleToggle = useCallback28(
16598
+ const handleToggle = useCallback29(
16225
16599
  (scope, checked) => {
16226
16600
  if (checked) {
16227
16601
  onChange([...value, scope]);
@@ -16289,12 +16663,12 @@ function OAuthScopeSelector({
16289
16663
  __name(OAuthScopeSelector, "OAuthScopeSelector");
16290
16664
 
16291
16665
  // src/features/oauth/components/OAuthClientSecretDisplay.tsx
16292
- import { useState as useState73, useCallback as useCallback29 } from "react";
16666
+ import { useState as useState73, useCallback as useCallback30 } from "react";
16293
16667
  import { Copy as Copy3, Check, AlertTriangle } from "lucide-react";
16294
16668
  import { jsx as jsx187, jsxs as jsxs116 } from "react/jsx-runtime";
16295
16669
  function OAuthClientSecretDisplay({ secret, onDismiss, open, clientName }) {
16296
16670
  const [copied, setCopied] = useState73(false);
16297
- const handleCopy = useCallback29(async () => {
16671
+ const handleCopy = useCallback30(async () => {
16298
16672
  try {
16299
16673
  await navigator.clipboard.writeText(secret);
16300
16674
  setCopied(true);
@@ -16303,7 +16677,7 @@ function OAuthClientSecretDisplay({ secret, onDismiss, open, clientName }) {
16303
16677
  console.error("Failed to copy to clipboard:", err);
16304
16678
  }
16305
16679
  }, [secret]);
16306
- const handleDismiss = useCallback29(() => {
16680
+ const handleDismiss = useCallback30(() => {
16307
16681
  setCopied(false);
16308
16682
  onDismiss();
16309
16683
  }, [onDismiss]);
@@ -16486,7 +16860,7 @@ function OAuthClientList({
16486
16860
  __name(OAuthClientList, "OAuthClientList");
16487
16861
 
16488
16862
  // src/features/oauth/components/OAuthClientForm.tsx
16489
- import { useState as useState74, useCallback as useCallback30 } from "react";
16863
+ import { useState as useState74, useCallback as useCallback31 } from "react";
16490
16864
  import { jsx as jsx190, jsxs as jsxs119 } from "react/jsx-runtime";
16491
16865
  function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false }) {
16492
16866
  const isEditMode = !!client;
@@ -16498,7 +16872,7 @@ function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false }) {
16498
16872
  isConfidential: client?.isConfidential ?? true
16499
16873
  });
16500
16874
  const [errors, setErrors] = useState74({});
16501
- const validate = useCallback30(() => {
16875
+ const validate = useCallback31(() => {
16502
16876
  const newErrors = {};
16503
16877
  if (!formState.name.trim()) {
16504
16878
  newErrors.name = "Application name is required";
@@ -16513,7 +16887,7 @@ function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false }) {
16513
16887
  setErrors(newErrors);
16514
16888
  return Object.keys(newErrors).length === 0;
16515
16889
  }, [formState]);
16516
- const handleSubmit = useCallback30(
16890
+ const handleSubmit = useCallback31(
16517
16891
  async (e) => {
16518
16892
  e.preventDefault();
16519
16893
  if (!validate()) return;
@@ -16620,7 +16994,7 @@ function OAuthClientForm({ client, onSubmit, onCancel, isLoading = false }) {
16620
16994
  __name(OAuthClientForm, "OAuthClientForm");
16621
16995
 
16622
16996
  // src/features/oauth/components/OAuthClientDetail.tsx
16623
- import { useState as useState75, useCallback as useCallback31 } from "react";
16997
+ import { useState as useState75, useCallback as useCallback32 } from "react";
16624
16998
  import { format as format2 } from "date-fns";
16625
16999
  import { Copy as Copy4, Check as Check2, RefreshCw as RefreshCw3, Pencil as Pencil2, Trash2 as Trash25, ExternalLink } from "lucide-react";
16626
17000
  import { Fragment as Fragment40, jsx as jsx191, jsxs as jsxs120 } from "react/jsx-runtime";
@@ -16636,7 +17010,7 @@ function OAuthClientDetail({
16636
17010
  const [showRegenerateConfirm, setShowRegenerateConfirm] = useState75(false);
16637
17011
  const [isDeleting, setIsDeleting] = useState75(false);
16638
17012
  const [isRegenerating, setIsRegenerating] = useState75(false);
16639
- const copyToClipboard2 = useCallback31(async (text, field) => {
17013
+ const copyToClipboard2 = useCallback32(async (text, field) => {
16640
17014
  try {
16641
17015
  await navigator.clipboard.writeText(text);
16642
17016
  setCopiedField(field);
@@ -16645,7 +17019,7 @@ function OAuthClientDetail({
16645
17019
  console.error("Failed to copy:", err);
16646
17020
  }
16647
17021
  }, []);
16648
- const handleDelete = useCallback31(async () => {
17022
+ const handleDelete = useCallback32(async () => {
16649
17023
  if (!onDelete) return;
16650
17024
  setIsDeleting(true);
16651
17025
  try {
@@ -16655,7 +17029,7 @@ function OAuthClientDetail({
16655
17029
  setShowDeleteConfirm(false);
16656
17030
  }
16657
17031
  }, [onDelete]);
16658
- const handleRegenerateSecret = useCallback31(async () => {
17032
+ const handleRegenerateSecret = useCallback32(async () => {
16659
17033
  if (!onRegenerateSecret) return;
16660
17034
  setIsRegenerating(true);
16661
17035
  try {
@@ -17231,7 +17605,7 @@ __name(WaitlistConfirmation, "WaitlistConfirmation");
17231
17605
  import { flexRender as flexRender2, getCoreRowModel as getCoreRowModel2, useReactTable as useReactTable2 } from "@tanstack/react-table";
17232
17606
  import { RefreshCw as RefreshCw4, Users as Users2 } from "lucide-react";
17233
17607
  import { useTranslations as useTranslations81 } from "next-intl";
17234
- import { useCallback as useCallback32, useEffect as useEffect58, useState as useState78 } from "react";
17608
+ import { useCallback as useCallback33, useEffect as useEffect58, useState as useState78 } from "react";
17235
17609
 
17236
17610
  // src/features/waitlist/hooks/useWaitlistTableStructure.tsx
17237
17611
  import { Send } from "lucide-react";
@@ -17332,7 +17706,7 @@ function WaitlistList() {
17332
17706
  const [total, setTotal] = useState78(0);
17333
17707
  const [isLoading, setIsLoading] = useState78(true);
17334
17708
  const [statusFilter, setStatusFilter] = useState78("all");
17335
- const loadEntries = useCallback32(async () => {
17709
+ const loadEntries = useCallback33(async () => {
17336
17710
  setIsLoading(true);
17337
17711
  try {
17338
17712
  const result = await WaitlistService.findMany({
@@ -17398,6 +17772,452 @@ function WaitlistList() {
17398
17772
  }
17399
17773
  __name(WaitlistList, "WaitlistList");
17400
17774
 
17775
+ // src/features/rbac/components/RbacContainer.tsx
17776
+ import { Loader2Icon as Loader2Icon2 } from "lucide-react";
17777
+ import { useTranslations as useTranslations86 } from "next-intl";
17778
+ import { useCallback as useCallback35, useEffect as useEffect59, useState as useState81 } from "react";
17779
+
17780
+ // src/features/rbac/components/RbacFeatureSection.tsx
17781
+ import { ChevronDownIcon as ChevronDownIcon8 } from "lucide-react";
17782
+ import { useTranslations as useTranslations84 } from "next-intl";
17783
+ import { useState as useState80 } from "react";
17784
+
17785
+ // src/features/rbac/components/RbacModuleTable.tsx
17786
+ import { RotateCcwIcon } from "lucide-react";
17787
+ import { useTranslations as useTranslations83 } from "next-intl";
17788
+
17789
+ // src/features/rbac/components/RbacPermissionPicker.tsx
17790
+ import { CheckIcon as CheckIcon9, MinusIcon as MinusIcon3, XIcon as XIcon8 } from "lucide-react";
17791
+ import { useTranslations as useTranslations82 } from "next-intl";
17792
+ import { useCallback as useCallback34, useState as useState79 } from "react";
17793
+
17794
+ // src/features/rbac/components/RbacPermissionCell.tsx
17795
+ import { CheckIcon as CheckIcon8, MinusIcon as MinusIcon2, XIcon as XIcon7 } from "lucide-react";
17796
+ import { jsx as jsx203, jsxs as jsxs132 } from "react/jsx-runtime";
17797
+ function RbacPermissionCell({
17798
+ value,
17799
+ originalValue,
17800
+ isRoleColumn = false,
17801
+ onClick
17802
+ }) {
17803
+ const isDirty = originalValue !== void 0 && value !== originalValue;
17804
+ if (isRoleColumn && (value === null || value === void 0)) {
17805
+ return /* @__PURE__ */ jsx203(
17806
+ "div",
17807
+ {
17808
+ onClick,
17809
+ className: cn(
17810
+ "flex h-8 w-full items-center justify-center rounded px-2 transition-colors hover:bg-muted cursor-pointer",
17811
+ isDirty && "ring-2 ring-amber-400/50"
17812
+ ),
17813
+ children: /* @__PURE__ */ jsx203(MinusIcon2, { className: "h-3.5 w-3.5 text-muted-foreground" })
17814
+ }
17815
+ );
17816
+ }
17817
+ if (value === true) {
17818
+ return /* @__PURE__ */ jsx203(
17819
+ "div",
17820
+ {
17821
+ onClick,
17822
+ className: cn(
17823
+ "flex h-8 w-full items-center justify-center rounded px-2 transition-colors hover:bg-muted cursor-pointer",
17824
+ isDirty && "ring-2 ring-amber-400/50"
17825
+ ),
17826
+ children: /* @__PURE__ */ jsxs132(Badge, { variant: "default", className: "bg-emerald-600 hover:bg-emerald-700 gap-1 text-xs", children: [
17827
+ /* @__PURE__ */ jsx203(CheckIcon8, { className: "h-3 w-3" }),
17828
+ /* @__PURE__ */ jsx203("span", { children: "true" })
17829
+ ] })
17830
+ }
17831
+ );
17832
+ }
17833
+ if (value === false) {
17834
+ return /* @__PURE__ */ jsx203(
17835
+ "div",
17836
+ {
17837
+ onClick,
17838
+ className: cn(
17839
+ "flex h-8 w-full items-center justify-center rounded px-2 transition-colors hover:bg-muted cursor-pointer",
17840
+ isDirty && "ring-2 ring-amber-400/50"
17841
+ ),
17842
+ children: /* @__PURE__ */ jsxs132(Badge, { variant: "destructive", className: "gap-1 text-xs", children: [
17843
+ /* @__PURE__ */ jsx203(XIcon7, { className: "h-3 w-3" }),
17844
+ /* @__PURE__ */ jsx203("span", { children: "false" })
17845
+ ] })
17846
+ }
17847
+ );
17848
+ }
17849
+ const displayValue = typeof value === "string" ? value : String(value);
17850
+ const truncated = displayValue.length > 20 ? displayValue.substring(0, 18) + "..." : displayValue;
17851
+ return /* @__PURE__ */ jsxs132(Tooltip2, { children: [
17852
+ /* @__PURE__ */ jsx203(
17853
+ TooltipTrigger,
17854
+ {
17855
+ onClick,
17856
+ className: cn(
17857
+ "flex h-8 w-full items-center justify-center rounded px-2 transition-colors hover:bg-muted cursor-pointer",
17858
+ isDirty && "ring-2 ring-amber-400/50"
17859
+ ),
17860
+ render: /* @__PURE__ */ jsx203("div", {}),
17861
+ children: /* @__PURE__ */ jsx203(Badge, { variant: "outline", className: "max-w-full truncate text-xs font-mono", children: truncated })
17862
+ }
17863
+ ),
17864
+ /* @__PURE__ */ jsx203(TooltipContent, { side: "top", className: "max-w-xs", children: /* @__PURE__ */ jsx203("p", { className: "font-mono text-xs break-all", children: displayValue }) })
17865
+ ] });
17866
+ }
17867
+ __name(RbacPermissionCell, "RbacPermissionCell");
17868
+
17869
+ // src/features/rbac/components/RbacPermissionPicker.tsx
17870
+ import { Fragment as Fragment42, jsx as jsx204, jsxs as jsxs133 } from "react/jsx-runtime";
17871
+ function RbacPermissionPicker({
17872
+ value,
17873
+ originalValue,
17874
+ isRoleColumn = false,
17875
+ knownSegments,
17876
+ onSetValue,
17877
+ onClear
17878
+ }) {
17879
+ const t = useTranslations82();
17880
+ const [open, setOpen] = useState79(false);
17881
+ const [customSegment, setCustomSegment] = useState79("");
17882
+ const currentSegments = typeof value === "string" ? value.split("|").filter(Boolean) : [];
17883
+ const toggleSegment = useCallback34(
17884
+ (segment) => {
17885
+ const newSegments = currentSegments.includes(segment) ? currentSegments.filter((s) => s !== segment) : [...currentSegments, segment];
17886
+ if (newSegments.length === 0) {
17887
+ onSetValue(false);
17888
+ } else {
17889
+ onSetValue(newSegments.join("|"));
17890
+ }
17891
+ },
17892
+ [currentSegments, onSetValue]
17893
+ );
17894
+ const addCustomSegment = useCallback34(() => {
17895
+ if (!customSegment.trim()) return;
17896
+ const segment = customSegment.trim();
17897
+ if (!currentSegments.includes(segment)) {
17898
+ const newSegments = [...currentSegments, segment];
17899
+ onSetValue(newSegments.join("|"));
17900
+ }
17901
+ setCustomSegment("");
17902
+ }, [customSegment, currentSegments, onSetValue]);
17903
+ return /* @__PURE__ */ jsxs133(Popover, { open, onOpenChange: setOpen, children: [
17904
+ /* @__PURE__ */ jsx204(PopoverTrigger, { children: /* @__PURE__ */ jsx204(RbacPermissionCell, { value, originalValue, isRoleColumn }) }),
17905
+ /* @__PURE__ */ jsx204(PopoverContent, { className: "w-72 p-3", align: "center", children: /* @__PURE__ */ jsxs133("div", { className: "space-y-3", children: [
17906
+ /* @__PURE__ */ jsxs133("div", { children: [
17907
+ /* @__PURE__ */ jsx204("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: t("rbac.quick_value") }),
17908
+ /* @__PURE__ */ jsxs133("div", { className: "flex gap-2", children: [
17909
+ /* @__PURE__ */ jsxs133(
17910
+ Button,
17911
+ {
17912
+ size: "sm",
17913
+ variant: value === true ? "default" : "outline",
17914
+ className: cn("flex-1 gap-1", value === true && "bg-emerald-600 hover:bg-emerald-700"),
17915
+ onClick: () => {
17916
+ onSetValue(true);
17917
+ setOpen(false);
17918
+ },
17919
+ children: [
17920
+ /* @__PURE__ */ jsx204(CheckIcon9, { className: "h-3 w-3" }),
17921
+ /* @__PURE__ */ jsx204("span", { children: "true" })
17922
+ ]
17923
+ }
17924
+ ),
17925
+ /* @__PURE__ */ jsxs133(
17926
+ Button,
17927
+ {
17928
+ size: "sm",
17929
+ variant: value === false ? "destructive" : "outline",
17930
+ className: "flex-1 gap-1",
17931
+ onClick: () => {
17932
+ onSetValue(false);
17933
+ setOpen(false);
17934
+ },
17935
+ children: [
17936
+ /* @__PURE__ */ jsx204(XIcon8, { className: "h-3 w-3" }),
17937
+ /* @__PURE__ */ jsx204("span", { children: "false" })
17938
+ ]
17939
+ }
17940
+ )
17941
+ ] })
17942
+ ] }),
17943
+ isRoleColumn && onClear && /* @__PURE__ */ jsxs133(Fragment42, { children: [
17944
+ /* @__PURE__ */ jsx204(Separator, {}),
17945
+ /* @__PURE__ */ jsxs133(
17946
+ Button,
17947
+ {
17948
+ size: "sm",
17949
+ variant: "ghost",
17950
+ className: "w-full gap-1 text-muted-foreground",
17951
+ onClick: () => {
17952
+ onClear();
17953
+ setOpen(false);
17954
+ },
17955
+ children: [
17956
+ /* @__PURE__ */ jsx204(MinusIcon3, { className: "h-3 w-3" }),
17957
+ t("rbac.inherit_from_defaults")
17958
+ ]
17959
+ }
17960
+ )
17961
+ ] }),
17962
+ knownSegments.length > 0 && /* @__PURE__ */ jsxs133(Fragment42, { children: [
17963
+ /* @__PURE__ */ jsx204(Separator, {}),
17964
+ /* @__PURE__ */ jsxs133("div", { children: [
17965
+ /* @__PURE__ */ jsx204("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: t("rbac.relationships") }),
17966
+ /* @__PURE__ */ jsx204("div", { className: "max-h-40 space-y-1 overflow-y-auto", children: knownSegments.map((segment) => /* @__PURE__ */ jsxs133(
17967
+ "label",
17968
+ {
17969
+ className: "flex items-center gap-2 rounded px-1 py-0.5 text-sm hover:bg-muted cursor-pointer",
17970
+ children: [
17971
+ /* @__PURE__ */ jsx204(
17972
+ Checkbox,
17973
+ {
17974
+ checked: currentSegments.includes(segment),
17975
+ onCheckedChange: () => toggleSegment(segment)
17976
+ }
17977
+ ),
17978
+ /* @__PURE__ */ jsx204("span", { className: "font-mono text-xs", children: segment })
17979
+ ]
17980
+ },
17981
+ segment
17982
+ )) }),
17983
+ /* @__PURE__ */ jsxs133("div", { className: "mt-2 flex gap-1", children: [
17984
+ /* @__PURE__ */ jsx204(
17985
+ Input,
17986
+ {
17987
+ value: customSegment,
17988
+ onChange: (e) => setCustomSegment(e.target.value),
17989
+ placeholder: t("rbac.custom_segment_placeholder"),
17990
+ className: "h-7 text-xs font-mono",
17991
+ onKeyDown: (e) => {
17992
+ if (e.key === "Enter") {
17993
+ e.preventDefault();
17994
+ addCustomSegment();
17995
+ }
17996
+ }
17997
+ }
17998
+ ),
17999
+ /* @__PURE__ */ jsx204(
18000
+ Button,
18001
+ {
18002
+ size: "sm",
18003
+ variant: "outline",
18004
+ className: "h-7 px-2 text-xs",
18005
+ onClick: addCustomSegment,
18006
+ disabled: !customSegment.trim(),
18007
+ children: "+"
18008
+ }
18009
+ )
18010
+ ] }),
18011
+ currentSegments.length > 0 && /* @__PURE__ */ jsxs133("div", { className: "mt-2 rounded bg-muted p-2", children: [
18012
+ /* @__PURE__ */ jsx204("p", { className: "text-xs text-muted-foreground mb-1", children: t("rbac.preview") }),
18013
+ /* @__PURE__ */ jsx204("p", { className: "text-xs font-mono break-all", children: currentSegments.join("|") })
18014
+ ] })
18015
+ ] })
18016
+ ] })
18017
+ ] }) })
18018
+ ] });
18019
+ }
18020
+ __name(RbacPermissionPicker, "RbacPermissionPicker");
18021
+
18022
+ // src/features/rbac/components/RbacModuleTable.tsx
18023
+ import { jsx as jsx205, jsxs as jsxs134 } from "react/jsx-runtime";
18024
+ var ACTION_LABELS = {
18025
+ read: "Read",
18026
+ create: "Create",
18027
+ update: "Update",
18028
+ delete: "Delete"
18029
+ };
18030
+ function RbacModuleTable({ module, roles, stateApi }) {
18031
+ const t = useTranslations83();
18032
+ const handleReset = /* @__PURE__ */ __name(() => {
18033
+ stateApi.resetModulePermissions(module.id, roles);
18034
+ }, "handleReset");
18035
+ return /* @__PURE__ */ jsxs134("div", { className: "rounded-lg border border-accent bg-card", children: [
18036
+ /* @__PURE__ */ jsxs134("div", { className: "flex items-center justify-between border-b px-4 py-2", children: [
18037
+ /* @__PURE__ */ jsx205("h4", { className: "text-sm font-medium", children: module.name }),
18038
+ /* @__PURE__ */ jsx205(
18039
+ Button,
18040
+ {
18041
+ variant: "ghost",
18042
+ size: "sm",
18043
+ onClick: handleReset,
18044
+ className: "h-7 px-2 text-muted-foreground hover:text-foreground",
18045
+ children: /* @__PURE__ */ jsx205(RotateCcwIcon, { className: "h-3.5 w-3.5" })
18046
+ }
18047
+ )
18048
+ ] }),
18049
+ /* @__PURE__ */ jsx205("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs134("table", { className: "w-full text-sm", children: [
18050
+ /* @__PURE__ */ jsx205("thead", { children: /* @__PURE__ */ jsxs134("tr", { className: "border-b bg-muted/50", children: [
18051
+ /* @__PURE__ */ jsx205("th", { className: "px-4 py-2 text-left text-xs font-medium text-muted-foreground w-40", children: t("rbac.role") }),
18052
+ ACTION_TYPES.map((actionType) => /* @__PURE__ */ jsx205(
18053
+ "th",
18054
+ {
18055
+ className: "px-2 py-2 text-center text-xs font-medium text-muted-foreground min-w-28",
18056
+ children: ACTION_LABELS[actionType]
18057
+ },
18058
+ actionType
18059
+ ))
18060
+ ] }) }),
18061
+ /* @__PURE__ */ jsxs134("tbody", { children: [
18062
+ /* @__PURE__ */ jsxs134("tr", { className: "border-b", children: [
18063
+ /* @__PURE__ */ jsx205("td", { className: "px-4 py-1 text-xs font-medium text-muted-foreground", children: t("rbac.defaults") }),
18064
+ ACTION_TYPES.map((actionType) => {
18065
+ const defaultValue = stateApi.getModuleDefaultPermission(module.id, actionType) ?? false;
18066
+ const originalDefaultValue = module.permissions[actionType] ?? false;
18067
+ return /* @__PURE__ */ jsx205("td", { className: "px-2 py-1", children: /* @__PURE__ */ jsx205(
18068
+ RbacPermissionPicker,
18069
+ {
18070
+ value: defaultValue,
18071
+ originalValue: originalDefaultValue,
18072
+ isRoleColumn: false,
18073
+ knownSegments: stateApi.getModuleRelationshipPaths(module.id),
18074
+ onSetValue: (value) => stateApi.setModuleDefaultPermission(module.id, actionType, value)
18075
+ }
18076
+ ) }, actionType);
18077
+ })
18078
+ ] }),
18079
+ roles.filter((role) => role.id !== COMPANY_ADMINISTRATOR_ROLE_ID).map((role) => /* @__PURE__ */ jsxs134("tr", { className: "border-b last:border-b-0", children: [
18080
+ /* @__PURE__ */ jsx205("td", { className: "px-4 py-1 text-xs font-medium text-muted-foreground", children: role.name }),
18081
+ ACTION_TYPES.map((actionType) => {
18082
+ const roleValue = stateApi.getRolePermission(role.id, module.id, actionType);
18083
+ const originalMapping = stateApi.original?.permissionMappings.find(
18084
+ (pm) => pm.roleId === role.id && pm.moduleId === module.id
18085
+ );
18086
+ const originalRoleValue = originalMapping ? originalMapping.permissions[actionType] ?? null : void 0;
18087
+ return /* @__PURE__ */ jsx205("td", { className: "px-2 py-1", children: /* @__PURE__ */ jsx205(
18088
+ RbacPermissionPicker,
18089
+ {
18090
+ value: roleValue,
18091
+ originalValue: originalRoleValue,
18092
+ isRoleColumn: true,
18093
+ knownSegments: stateApi.getModuleRelationshipPaths(module.id),
18094
+ onSetValue: (value) => stateApi.setRolePermission(role.id, module.id, actionType, value),
18095
+ onClear: () => stateApi.clearRolePermission(role.id, module.id, actionType)
18096
+ }
18097
+ ) }, actionType);
18098
+ })
18099
+ ] }, role.id))
18100
+ ] })
18101
+ ] }) })
18102
+ ] });
18103
+ }
18104
+ __name(RbacModuleTable, "RbacModuleTable");
18105
+
18106
+ // src/features/rbac/components/RbacFeatureSection.tsx
18107
+ import { jsx as jsx206, jsxs as jsxs135 } from "react/jsx-runtime";
18108
+ function RbacFeatureSection({ feature, roles, stateApi }) {
18109
+ const t = useTranslations84();
18110
+ const [isOpen, setIsOpen] = useState80(true);
18111
+ const featureIsCore = stateApi.getFeatureIsCore(feature.id);
18112
+ return /* @__PURE__ */ jsx206(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs135("div", { className: "rounded-lg border bg-card", children: [
18113
+ /* @__PURE__ */ jsx206(CollapsibleTrigger, { className: "w-full", children: /* @__PURE__ */ jsxs135("div", { className: "flex cursor-pointer items-center justify-between px-4 py-3 hover:bg-muted/50 transition-colors", children: [
18114
+ /* @__PURE__ */ jsxs135("div", { className: "flex items-center gap-3", children: [
18115
+ /* @__PURE__ */ jsx206(
18116
+ ChevronDownIcon8,
18117
+ {
18118
+ className: cn("h-4 w-4 text-muted-foreground transition-transform", !isOpen && "-rotate-90")
18119
+ }
18120
+ ),
18121
+ /* @__PURE__ */ jsx206("h3", { className: "text-base font-semibold", children: feature.name }),
18122
+ /* @__PURE__ */ jsx206("span", { className: "text-xs text-muted-foreground", children: t("rbac.module_count", { count: feature.modules.length }) })
18123
+ ] }),
18124
+ /* @__PURE__ */ jsxs135("div", { className: "flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [
18125
+ /* @__PURE__ */ jsx206("span", { className: "text-xs text-muted-foreground", children: t("rbac.core") }),
18126
+ /* @__PURE__ */ jsx206(
18127
+ Switch,
18128
+ {
18129
+ checked: featureIsCore,
18130
+ onCheckedChange: (checked) => stateApi.setFeatureIsCore(feature.id, checked),
18131
+ className: "data-checked:bg-accent data-unchecked:bg-gray-300"
18132
+ }
18133
+ )
18134
+ ] })
18135
+ ] }) }),
18136
+ /* @__PURE__ */ jsx206(CollapsibleContent, { children: /* @__PURE__ */ jsxs135("div", { className: "space-y-3 p-4 pt-0", children: [
18137
+ feature.modules.map((mod) => /* @__PURE__ */ jsx206(RbacModuleTable, { module: mod, roles, stateApi }, mod.id)),
18138
+ feature.modules.length === 0 && /* @__PURE__ */ jsx206("p", { className: "text-sm text-muted-foreground italic py-4 text-center", children: t("rbac.no_modules") })
18139
+ ] }) })
18140
+ ] }) });
18141
+ }
18142
+ __name(RbacFeatureSection, "RbacFeatureSection");
18143
+
18144
+ // src/features/rbac/components/RbacToolbar.tsx
18145
+ import { DownloadIcon, RotateCcwIcon as RotateCcwIcon2 } from "lucide-react";
18146
+ import { useTranslations as useTranslations85 } from "next-intl";
18147
+ import { jsx as jsx207, jsxs as jsxs136 } from "react/jsx-runtime";
18148
+ function RbacToolbar({ isDirty, onGenerate, onReset }) {
18149
+ const t = useTranslations85();
18150
+ return /* @__PURE__ */ jsxs136("div", { className: "flex items-center justify-between rounded-lg border bg-card px-4 py-3", children: [
18151
+ /* @__PURE__ */ jsxs136("div", { className: "flex items-center gap-3", children: [
18152
+ /* @__PURE__ */ jsx207("h2", { className: "text-lg font-semibold", children: t("rbac.title") }),
18153
+ isDirty && /* @__PURE__ */ jsx207(Badge, { variant: "outline", className: "border-amber-400 text-amber-600", children: t("rbac.unsaved_changes") })
18154
+ ] }),
18155
+ /* @__PURE__ */ jsxs136("div", { className: "flex items-center gap-2", children: [
18156
+ /* @__PURE__ */ jsxs136(Button, { variant: "outline", size: "sm", onClick: onReset, disabled: !isDirty, className: "gap-1", children: [
18157
+ /* @__PURE__ */ jsx207(RotateCcwIcon2, { className: "h-3.5 w-3.5" }),
18158
+ t("rbac.reset")
18159
+ ] }),
18160
+ /* @__PURE__ */ jsxs136(Button, { size: "sm", onClick: onGenerate, disabled: !isDirty, className: "gap-1", children: [
18161
+ /* @__PURE__ */ jsx207(DownloadIcon, { className: "h-3.5 w-3.5" }),
18162
+ t("rbac.generate_migration")
18163
+ ] })
18164
+ ] })
18165
+ ] });
18166
+ }
18167
+ __name(RbacToolbar, "RbacToolbar");
18168
+
18169
+ // src/features/rbac/components/RbacContainer.tsx
18170
+ import { jsx as jsx208, jsxs as jsxs137 } from "react/jsx-runtime";
18171
+ function RbacContainer() {
18172
+ const t = useTranslations86();
18173
+ const stateApi = useRbacState();
18174
+ const [loading, setLoading] = useState81(true);
18175
+ const [error, setError] = useState81(null);
18176
+ useEffect59(() => {
18177
+ async function fetchData() {
18178
+ try {
18179
+ setLoading(true);
18180
+ const [features, roles, permissionMappings, modulePaths] = await Promise.all([
18181
+ RbacService.getFeatures(),
18182
+ RbacService.getRoles(),
18183
+ RbacService.getPermissionMappings(),
18184
+ RbacService.getModuleRelationshipPaths()
18185
+ ]);
18186
+ stateApi.init(features, roles, permissionMappings, modulePaths);
18187
+ } catch (err) {
18188
+ console.error("Failed to load RBAC configuration:", err);
18189
+ setError(t("rbac.loading_error"));
18190
+ } finally {
18191
+ setLoading(false);
18192
+ }
18193
+ }
18194
+ __name(fetchData, "fetchData");
18195
+ fetchData();
18196
+ }, [t]);
18197
+ const handleGenerate = useCallback35(() => {
18198
+ const effective = stateApi.getEffectiveConfiguration();
18199
+ if (!effective) return;
18200
+ const content = generateMigrationFile({
18201
+ features: effective.features,
18202
+ roles: effective.roles,
18203
+ rolePermissionsMap: effective.rolePermissionsMap
18204
+ });
18205
+ downloadMigrationFile(content);
18206
+ }, [stateApi]);
18207
+ if (loading) {
18208
+ return /* @__PURE__ */ jsx208("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx208(Loader2Icon2, { className: "h-8 w-8 animate-spin text-muted-foreground" }) });
18209
+ }
18210
+ if (error) {
18211
+ return /* @__PURE__ */ jsx208("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx208("p", { className: "text-destructive", children: error }) });
18212
+ }
18213
+ if (!stateApi.original) return null;
18214
+ return /* @__PURE__ */ jsxs137(RoundPageContainer, { children: [
18215
+ /* @__PURE__ */ jsx208(RbacToolbar, { isDirty: stateApi.isDirty, onGenerate: handleGenerate, onReset: stateApi.reset }),
18216
+ stateApi.original.features.map((feature) => /* @__PURE__ */ jsx208(RbacFeatureSection, { feature, roles: stateApi.original.roles, stateApi }, feature.id))
18217
+ ] });
18218
+ }
18219
+ __name(RbacContainer, "RbacContainer");
18220
+
17401
18221
  export {
17402
18222
  JsonApiProvider,
17403
18223
  useJsonApiGet,
@@ -17836,6 +18656,15 @@ export {
17836
18656
  WaitlistSuccessState,
17837
18657
  WaitlistConfirmation,
17838
18658
  WaitlistList,
18659
+ useRbacState,
18660
+ generateMigrationFile,
18661
+ downloadMigrationFile,
18662
+ RbacPermissionCell,
18663
+ RbacPermissionPicker,
18664
+ RbacModuleTable,
18665
+ RbacFeatureSection,
18666
+ RbacToolbar,
18667
+ RbacContainer,
17839
18668
  AddUserToRole,
17840
18669
  UserAvatarEditor,
17841
18670
  UserDeleter,
@@ -17863,4 +18692,4 @@ export {
17863
18692
  useOAuthClients,
17864
18693
  useOAuthClient
17865
18694
  };
17866
- //# sourceMappingURL=chunk-BTLJZIDS.mjs.map
18695
+ //# sourceMappingURL=chunk-G5473JP3.mjs.map