@jmruthers/pace-core 0.5.1 → 0.5.4

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 (210) hide show
  1. package/dist/{DataTable-GX3XERFJ.js → DataTable-ZQDRE46Q.js} +7 -6
  2. package/dist/{PublicLoadingSpinner-DztrzuJr.d.ts → PublicLoadingSpinner-Bq_-BeK-.d.ts} +1 -1
  3. package/dist/RBACProvider-BO4ilsQB.d.ts +63 -0
  4. package/dist/{UnifiedAuthProvider-w66zSCUf.d.ts → UnifiedAuthProvider-DGQsy-vY.d.ts} +2 -59
  5. package/dist/{api-ETQ6YJ3C.js → api-H5A3H4IR.js} +2 -2
  6. package/dist/{chunk-T3XIA4AJ.js → chunk-5H3C2SWM.js} +14 -16
  7. package/dist/chunk-5H3C2SWM.js.map +1 -0
  8. package/dist/chunk-5SIXIV7R.js +1925 -0
  9. package/dist/chunk-5SIXIV7R.js.map +1 -0
  10. package/dist/chunk-GNTALZV3.js +17 -0
  11. package/dist/chunk-GNTALZV3.js.map +1 -0
  12. package/dist/{chunk-C5G2A4PO.js → chunk-GWSBHC4J.js} +6 -6
  13. package/dist/{chunk-XJK2J4N6.js → chunk-HD7PYDUV.js} +4 -6
  14. package/dist/{chunk-XJK2J4N6.js.map → chunk-HD7PYDUV.js.map} +1 -1
  15. package/dist/{chunk-TGDCLPP2.js → chunk-HXX35Q2M.js} +6 -21
  16. package/dist/chunk-HXX35Q2M.js.map +1 -0
  17. package/dist/{chunk-5EL3KHOQ.js → chunk-K6B7BLSE.js} +2 -2
  18. package/dist/{chunk-GSNM5D6H.js → chunk-M4RW7PIP.js} +4 -4
  19. package/dist/{chunk-U6JDHVC2.js → chunk-PVMYVQSM.js} +6 -8
  20. package/dist/{chunk-U6JDHVC2.js.map → chunk-PVMYVQSM.js.map} +1 -1
  21. package/dist/{chunk-6CR3MRZN.js → chunk-QKHFMQ5R.js} +372 -11
  22. package/dist/{chunk-6CR3MRZN.js.map → chunk-QKHFMQ5R.js.map} +1 -1
  23. package/dist/chunk-QVYBYGT2.js +428 -0
  24. package/dist/chunk-QVYBYGT2.js.map +1 -0
  25. package/dist/{chunk-OEGRKULD.js → chunk-WJARTBCT.js} +56 -1
  26. package/dist/chunk-WJARTBCT.js.map +1 -0
  27. package/dist/components.d.ts +4 -3
  28. package/dist/components.js +16 -162
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.d.ts +2 -2
  31. package/dist/hooks.js +7 -9
  32. package/dist/hooks.js.map +1 -1
  33. package/dist/index.d.ts +8 -6
  34. package/dist/index.js +152 -17
  35. package/dist/index.js.map +1 -1
  36. package/dist/providers.d.ts +3 -2
  37. package/dist/providers.js +6 -12
  38. package/dist/rbac/index.d.ts +167 -98
  39. package/dist/rbac/index.js +48 -1881
  40. package/dist/rbac/index.js.map +1 -1
  41. package/dist/styles/core.css +0 -55
  42. package/dist/types.d.ts +2 -2
  43. package/dist/{unified-CM7T0aTK.d.ts → unified-CMPjE_fv.d.ts} +1 -1
  44. package/dist/{usePublicRouteParams-B6i0KtXW.d.ts → usePublicRouteParams-B2OcAsur.d.ts} +1 -1
  45. package/dist/utils.js +12 -14
  46. package/dist/utils.js.map +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +73 -0
  49. package/docs/api/classes/MissingUserContextError.md +66 -0
  50. package/docs/api/classes/OrganisationContextRequiredError.md +66 -0
  51. package/docs/api/classes/PermissionDeniedError.md +73 -0
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +270 -0
  54. package/docs/api/classes/RBACCache.md +284 -0
  55. package/docs/api/classes/RBACEngine.md +141 -0
  56. package/docs/api/classes/RBACError.md +76 -0
  57. package/docs/api/classes/RBACNotInitializedError.md +66 -0
  58. package/docs/api/classes/SecureSupabaseClient.md +135 -0
  59. package/docs/api/interfaces/AggregateConfig.md +1 -1
  60. package/docs/api/interfaces/ButtonProps.md +1 -1
  61. package/docs/api/interfaces/CardProps.md +1 -1
  62. package/docs/api/interfaces/ColorPalette.md +1 -1
  63. package/docs/api/interfaces/ColorShade.md +1 -1
  64. package/docs/api/interfaces/DataAccessRecord.md +96 -0
  65. package/docs/api/interfaces/DataTableAction.md +1 -1
  66. package/docs/api/interfaces/DataTableColumn.md +1 -1
  67. package/docs/api/interfaces/DataTableProps.md +1 -1
  68. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  69. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  70. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +235 -0
  71. package/docs/api/interfaces/EventContextType.md +1 -1
  72. package/docs/api/interfaces/EventLogoProps.md +1 -1
  73. package/docs/api/interfaces/EventProviderProps.md +1 -1
  74. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  75. package/docs/api/interfaces/FileUploadProps.md +1 -1
  76. package/docs/api/interfaces/FooterProps.md +1 -1
  77. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  78. package/docs/api/interfaces/InputProps.md +1 -1
  79. package/docs/api/interfaces/LabelProps.md +1 -1
  80. package/docs/api/interfaces/LoginFormProps.md +1 -1
  81. package/docs/api/interfaces/NavigationAccessRecord.md +107 -0
  82. package/docs/api/interfaces/NavigationContextType.md +164 -0
  83. package/docs/api/interfaces/NavigationGuardProps.md +139 -0
  84. package/docs/api/interfaces/NavigationItem.md +1 -1
  85. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  86. package/docs/api/interfaces/NavigationProviderProps.md +117 -0
  87. package/docs/api/interfaces/Organisation.md +1 -1
  88. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  89. package/docs/api/interfaces/OrganisationMembership.md +2 -2
  90. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  91. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  92. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  93. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  94. package/docs/api/interfaces/PageAccessRecord.md +85 -0
  95. package/docs/api/interfaces/PagePermissionContextType.md +140 -0
  96. package/docs/api/interfaces/PagePermissionGuardProps.md +153 -0
  97. package/docs/api/interfaces/PagePermissionProviderProps.md +119 -0
  98. package/docs/api/interfaces/PaletteData.md +1 -1
  99. package/docs/api/interfaces/PermissionEnforcerProps.md +153 -0
  100. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  101. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  102. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  103. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  104. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  105. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  106. package/docs/api/interfaces/RBACConfig.md +99 -0
  107. package/docs/api/interfaces/RBACContextType.md +474 -0
  108. package/docs/api/interfaces/RBACLogger.md +112 -0
  109. package/docs/api/interfaces/RBACProviderProps.md +107 -0
  110. package/docs/api/interfaces/RoleBasedRouterContextType.md +151 -0
  111. package/docs/api/interfaces/RoleBasedRouterProps.md +156 -0
  112. package/docs/api/interfaces/RouteAccessRecord.md +107 -0
  113. package/docs/api/interfaces/RouteConfig.md +121 -0
  114. package/docs/api/interfaces/SecureDataContextType.md +168 -0
  115. package/docs/api/interfaces/SecureDataProviderProps.md +132 -0
  116. package/docs/api/interfaces/StorageConfig.md +1 -1
  117. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  118. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  119. package/docs/api/interfaces/StorageListOptions.md +1 -1
  120. package/docs/api/interfaces/StorageListResult.md +1 -1
  121. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  122. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  123. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  124. package/docs/api/interfaces/StyleImport.md +1 -1
  125. package/docs/api/interfaces/ToastActionElement.md +1 -1
  126. package/docs/api/interfaces/ToastProps.md +1 -1
  127. package/docs/api/interfaces/UnifiedAuthContextType.md +85 -85
  128. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  129. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  130. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  131. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  132. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  133. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  134. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  135. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  136. package/docs/api/interfaces/UserEventAccess.md +11 -11
  137. package/docs/api/interfaces/UserMenuProps.md +1 -1
  138. package/docs/api/interfaces/UserProfile.md +1 -1
  139. package/docs/api/modules.md +2244 -3
  140. package/docs/migration-guide.md +43 -18
  141. package/docs/styles/README.md +187 -98
  142. package/docs/usage.md +32 -7
  143. package/package.json +2 -2
  144. package/src/components/Footer/Footer.test.tsx +482 -0
  145. package/src/components/Form/Form.test.tsx +1158 -0
  146. package/src/components/Header/Header.test.tsx +582 -0
  147. package/src/components/Header/Header.tsx +1 -1
  148. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +489 -0
  149. package/src/components/Input/Input.test.tsx +466 -0
  150. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +450 -0
  151. package/src/components/LoginForm/LoginForm.test.tsx +816 -0
  152. package/src/components/NavigationMenu/NavigationMenu.test.tsx +883 -0
  153. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +748 -0
  154. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +891 -0
  155. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +475 -0
  156. package/src/components/PasswordReset/PasswordChangeForm.test.tsx +621 -0
  157. package/src/components/PasswordReset/PasswordResetForm.test.tsx +605 -0
  158. package/src/components/Select/Select.test.tsx +948 -0
  159. package/src/components/SuperAdminGuard.tsx +1 -1
  160. package/src/components/Toast/Toast.test.tsx +586 -0
  161. package/src/components/Tooltip/Tooltip.test.tsx +852 -0
  162. package/src/components/UserMenu/UserMenu.test.tsx +702 -0
  163. package/src/components/UserMenu/UserMenu.tsx +2 -2
  164. package/src/hooks/useDebounce.test.ts +375 -0
  165. package/src/hooks/useOrganisationPermissions.test.ts +528 -0
  166. package/src/hooks/useOrganisationSecurity.test.ts +734 -0
  167. package/src/hooks/usePermissionCache.test.ts +542 -0
  168. package/src/hooks/usePermissionCache.ts +1 -1
  169. package/src/index.ts +2 -3
  170. package/src/providers/UnifiedAuthProvider.tsx +2 -2
  171. package/src/providers/index.ts +3 -1
  172. package/src/rbac/__tests__/integration.test.tsx +218 -0
  173. package/src/rbac/api.test.ts +952 -0
  174. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +843 -0
  175. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1007 -0
  176. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +806 -0
  177. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +741 -0
  178. package/src/rbac/hooks/index.ts +21 -0
  179. package/src/rbac/hooks/useCan.test.ts +461 -0
  180. package/src/rbac/hooks/usePermissions.test.ts +364 -0
  181. package/src/rbac/hooks/usePermissions.ts +567 -0
  182. package/src/rbac/hooks/useRBAC.simple.test.ts +90 -0
  183. package/src/rbac/hooks/useRBAC.test.ts +551 -0
  184. package/src/{hooks → rbac/hooks}/useRBAC.ts +7 -7
  185. package/src/rbac/index.ts +5 -10
  186. package/src/{providers → rbac/providers}/RBACProvider.tsx +6 -6
  187. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +687 -0
  188. package/src/rbac/providers/index.ts +11 -0
  189. package/src/styles/core.css +0 -55
  190. package/src/utils/formatDate.test.ts +241 -0
  191. package/dist/chunk-AUE24LVR.js +0 -268
  192. package/dist/chunk-AUE24LVR.js.map +0 -1
  193. package/dist/chunk-COBPIXXQ.js +0 -379
  194. package/dist/chunk-COBPIXXQ.js.map +0 -1
  195. package/dist/chunk-OEGRKULD.js.map +0 -1
  196. package/dist/chunk-OYRY44Q2.js +0 -62
  197. package/dist/chunk-OYRY44Q2.js.map +0 -1
  198. package/dist/chunk-T3XIA4AJ.js.map +0 -1
  199. package/dist/chunk-TGDCLPP2.js.map +0 -1
  200. package/src/components/RBAC/PagePermissionGuard.tsx +0 -287
  201. package/src/components/RBAC/RBACGuard.tsx +0 -143
  202. package/src/components/RBAC/RBACProvider.tsx +0 -186
  203. package/src/components/RBAC/RoleBasedContent.tsx +0 -129
  204. package/src/components/RBAC/index.ts +0 -23
  205. package/src/rbac/hooks.ts +0 -570
  206. /package/dist/{DataTable-GX3XERFJ.js.map → DataTable-ZQDRE46Q.js.map} +0 -0
  207. /package/dist/{api-ETQ6YJ3C.js.map → api-H5A3H4IR.js.map} +0 -0
  208. /package/dist/{chunk-C5G2A4PO.js.map → chunk-GWSBHC4J.js.map} +0 -0
  209. /package/dist/{chunk-5EL3KHOQ.js.map → chunk-K6B7BLSE.js.map} +0 -0
  210. /package/dist/{chunk-GSNM5D6H.js.map → chunk-M4RW7PIP.js.map} +0 -0
@@ -1,379 +0,0 @@
1
- import {
2
- init_UnifiedAuthProvider,
3
- useUnifiedAuth
4
- } from "./chunk-6CR3MRZN.js";
5
- import {
6
- init_organisationContext,
7
- setOrganisationContext
8
- } from "./chunk-OEGRKULD.js";
9
- import {
10
- DebugLogger,
11
- init_debugLogger
12
- } from "./chunk-OYRY44Q2.js";
13
- import {
14
- __esm,
15
- __export
16
- } from "./chunk-PLDDJCW6.js";
17
-
18
- // src/providers/OrganisationProvider.tsx
19
- var OrganisationProvider_exports = {};
20
- __export(OrganisationProvider_exports, {
21
- OrganisationProvider: () => OrganisationProvider,
22
- useOrganisations: () => useOrganisations
23
- });
24
- import { createContext, useContext, useState, useEffect, useCallback, useMemo } from "react";
25
- import { useNavigate } from "react-router-dom";
26
- import { jsx, jsxs } from "react/jsx-runtime";
27
- function OrganisationProvider({ children }) {
28
- const [selectedOrganisation, setSelectedOrganisation] = useState(null);
29
- const [organisations, setOrganisations] = useState([]);
30
- const [userMemberships, setUserMemberships] = useState([]);
31
- const [roleMapState, setRoleMapState] = useState(/* @__PURE__ */ new Map());
32
- const [isLoading, setIsLoading] = useState(true);
33
- const [error, setError] = useState(null);
34
- const [isContextReady, setIsContextReady] = useState(false);
35
- const { user, session, supabase, signOut } = useUnifiedAuth();
36
- let navigate = null;
37
- try {
38
- navigate = useNavigate();
39
- } catch (error2) {
40
- navigate = null;
41
- }
42
- const setDatabaseOrganisationContext = useCallback(async (organisation) => {
43
- if (!supabase || !session) {
44
- console.warn("[OrganisationProvider] No Supabase client or session available for setting organisation context");
45
- setIsContextReady(false);
46
- return;
47
- }
48
- try {
49
- await setOrganisationContext(supabase, organisation.id);
50
- DebugLogger.log("OrganisationProvider", "Database organisation context set to:", organisation.display_name);
51
- setIsContextReady(true);
52
- } catch (error2) {
53
- console.error("[OrganisationProvider] Failed to set database organisation context:", error2);
54
- setIsContextReady(false);
55
- }
56
- }, [supabase, session]);
57
- useEffect(() => {
58
- if (selectedOrganisation && supabase && session) {
59
- setIsContextReady(false);
60
- (async () => {
61
- await setDatabaseOrganisationContext(selectedOrganisation);
62
- })();
63
- } else {
64
- setIsContextReady(false);
65
- }
66
- }, [selectedOrganisation, setDatabaseOrganisationContext, supabase, session]);
67
- const loadUserOrganisations = useCallback(async () => {
68
- if (!user || !session || !supabase) {
69
- DebugLogger.log("OrganisationProvider", "Clearing organisation state - no user, session, or supabase client");
70
- setSelectedOrganisation(null);
71
- setOrganisations([]);
72
- setUserMemberships([]);
73
- setIsLoading(false);
74
- setError(null);
75
- return;
76
- }
77
- setIsLoading(true);
78
- setError(null);
79
- try {
80
- DebugLogger.log("OrganisationProvider", "Loading organisations for user:", user.id);
81
- let memberships, membershipError;
82
- try {
83
- const result = await supabase.from("rbac_organisation_roles").select(`
84
- id,
85
- user_id,
86
- organisation_id,
87
- role,
88
- status,
89
- granted_at,
90
- granted_by,
91
- revoked_at,
92
- revoked_by,
93
- notes,
94
- created_at,
95
- updated_at
96
- `).eq("user_id", user.id).eq("status", "active").is("revoked_at", null).in("role", ["org_admin", "leader", "member"]);
97
- memberships = result.data;
98
- membershipError = result.error;
99
- } catch (queryError) {
100
- membershipError = queryError;
101
- }
102
- if (membershipError) {
103
- console.error("[OrganisationProvider] Error loading memberships:", membershipError);
104
- throw membershipError;
105
- }
106
- DebugLogger.log("OrganisationProvider", "Raw memberships data:", memberships);
107
- if (!memberships || memberships.length === 0) {
108
- throw new Error("User has no active organisation memberships");
109
- }
110
- const organisationIds = memberships.map((m) => m.organisation_id);
111
- const { data: organisations2, error: orgError } = await supabase.from("organisations").select("id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at").in("id", organisationIds);
112
- if (orgError) {
113
- console.error("[OrganisationProvider] Error loading organisations:", orgError);
114
- throw orgError;
115
- }
116
- const roleMap = /* @__PURE__ */ new Map();
117
- memberships?.forEach((membership) => {
118
- roleMap.set(membership.organisation_id, membership.role);
119
- });
120
- const orgs = organisations2;
121
- const activeOrgs = orgs.filter((org) => org.is_active);
122
- if (activeOrgs.length === 0) {
123
- throw new Error("User has no access to active organisations");
124
- }
125
- DebugLogger.log("OrganisationProvider", "Active organisations:", activeOrgs);
126
- setOrganisations(activeOrgs);
127
- setUserMemberships(memberships);
128
- setRoleMapState(roleMap);
129
- let initialOrg = null;
130
- try {
131
- const persistedOrgString = localStorage.getItem(STORAGE_KEYS.SELECTED_ORGANISATION);
132
- if (persistedOrgString) {
133
- const persistedOrg = JSON.parse(persistedOrgString);
134
- const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
135
- if (validPersistedOrg) {
136
- initialOrg = validPersistedOrg;
137
- DebugLogger.log("OrganisationProvider", "Restored persisted organisation:", initialOrg.display_name);
138
- }
139
- }
140
- } catch (storageError) {
141
- console.warn("[OrganisationProvider] Failed to restore persisted organisation:", storageError);
142
- }
143
- if (!initialOrg) {
144
- const adminMembership = memberships.find((m) => m.role === "org_admin");
145
- if (adminMembership) {
146
- const foundOrg = organisations2.find((org) => org.id === adminMembership.organisation_id);
147
- if (foundOrg) {
148
- initialOrg = foundOrg;
149
- DebugLogger.log("OrganisationProvider", "Selected org_admin organisation:", initialOrg.display_name);
150
- }
151
- }
152
- }
153
- if (!initialOrg) {
154
- initialOrg = activeOrgs[0];
155
- DebugLogger.log("OrganisationProvider", "Selected first organisation:", initialOrg.display_name);
156
- }
157
- if (!initialOrg) {
158
- throw new Error("No valid organisation found for user");
159
- }
160
- setSelectedOrganisation(initialOrg);
161
- localStorage.setItem(STORAGE_KEYS.SELECTED_ORGANISATION, JSON.stringify(initialOrg));
162
- DebugLogger.log("OrganisationProvider", "Organisation context established:", {
163
- selectedOrganisation: initialOrg.display_name,
164
- totalOrganisations: activeOrgs.length,
165
- userRole: roleMap.get(initialOrg.id)
166
- });
167
- } catch (err) {
168
- console.error("[OrganisationProvider] Failed to load organisations:", err);
169
- setError(err);
170
- setSelectedOrganisation(null);
171
- setOrganisations([]);
172
- setUserMemberships([]);
173
- localStorage.removeItem(STORAGE_KEYS.SELECTED_ORGANISATION);
174
- } finally {
175
- setIsLoading(false);
176
- }
177
- }, [user, session, supabase]);
178
- useEffect(() => {
179
- loadUserOrganisations();
180
- }, [loadUserOrganisations]);
181
- const handleLogoutAndRedirect = useCallback(async () => {
182
- try {
183
- await signOut();
184
- if (navigate) {
185
- navigate("/login", { replace: true });
186
- } else {
187
- window.location.href = "/login";
188
- }
189
- } catch (error2) {
190
- console.error("[OrganisationProvider] Error during logout:", error2);
191
- if (navigate) {
192
- navigate("/login", { replace: true });
193
- } else {
194
- window.location.href = "/login";
195
- }
196
- }
197
- }, [signOut, navigate]);
198
- const ensureOrganisationContext = useCallback(() => {
199
- if (!selectedOrganisation) {
200
- throw new Error("Organisation context is required but not available");
201
- }
202
- return selectedOrganisation;
203
- }, [selectedOrganisation]);
204
- const getUserRole = useCallback((orgId) => {
205
- const targetOrgId = orgId || selectedOrganisation?.id;
206
- if (!targetOrgId) return "no_access";
207
- return roleMapState.get(targetOrgId) || "no_access";
208
- }, [roleMapState, selectedOrganisation]);
209
- const validateOrganisationAccess = useCallback((orgId) => {
210
- return userMemberships.some(
211
- (m) => m.organisation_id === orgId && m.status === "active" && m.revoked_at === null
212
- );
213
- }, [userMemberships]);
214
- const switchOrganisation = useCallback(async (orgId) => {
215
- DebugLogger.log("OrganisationProvider", "Switching to organisation:", orgId);
216
- if (!validateOrganisationAccess(orgId)) {
217
- throw new Error(`User does not have access to organisation ${orgId}`);
218
- }
219
- const targetOrg = organisations.find((org) => org.id === orgId);
220
- if (!targetOrg) {
221
- throw new Error(`Organisation ${orgId} not found in user's organisations`);
222
- }
223
- setSelectedOrganisation(targetOrg);
224
- localStorage.setItem(STORAGE_KEYS.SELECTED_ORGANISATION, JSON.stringify(targetOrg));
225
- await setDatabaseOrganisationContext(targetOrg);
226
- DebugLogger.log("OrganisationProvider", "Switched to organisation:", targetOrg.display_name);
227
- }, [organisations, validateOrganisationAccess, setDatabaseOrganisationContext]);
228
- const refreshOrganisations = useCallback(async () => {
229
- if (!user || !session || !supabase) return;
230
- setIsLoading(true);
231
- }, [user, session, supabase]);
232
- const getPrimaryOrganisation = useCallback(() => {
233
- const rolePriority = ["org_admin", "leader", "member"];
234
- for (const role of rolePriority) {
235
- const membership = userMemberships.find((m) => m.role === role);
236
- if (membership) {
237
- return organisations.find((org) => org.id === membership.organisation_id) || null;
238
- }
239
- }
240
- return null;
241
- }, [userMemberships, organisations]);
242
- const isOrganisationSecure = useCallback(() => {
243
- return !!(selectedOrganisation && user);
244
- }, [selectedOrganisation, user]);
245
- const buildOrganisationHierarchy = useCallback((orgs) => {
246
- const orgMap = /* @__PURE__ */ new Map();
247
- orgs.forEach((org) => orgMap.set(org.id, org));
248
- const roots = [];
249
- orgs.forEach((org) => {
250
- if (!org.parent_id) {
251
- roots.push({
252
- organisation: org,
253
- children: [],
254
- depth: 0
255
- });
256
- }
257
- });
258
- return roots;
259
- }, []);
260
- const hasValidOrganisationContext = useMemo(() => {
261
- return !!(selectedOrganisation && !isLoading && !error && isContextReady);
262
- }, [selectedOrganisation, isLoading, error, isContextReady]);
263
- const contextValue = useMemo(() => {
264
- if (!selectedOrganisation) {
265
- const placeholderOrg = {
266
- id: "",
267
- name: "",
268
- display_name: "",
269
- subscription_tier: "standard",
270
- settings: {},
271
- is_active: false,
272
- created_at: "",
273
- updated_at: ""
274
- };
275
- return {
276
- selectedOrganisation: placeholderOrg,
277
- organisations: [],
278
- userMemberships: [],
279
- isLoading,
280
- error,
281
- hasValidOrganisationContext: false,
282
- setSelectedOrganisation: () => {
283
- },
284
- switchOrganisation: async () => {
285
- },
286
- getUserRole: () => "no_access",
287
- validateOrganisationAccess: () => false,
288
- refreshOrganisations: async () => {
289
- },
290
- ensureOrganisationContext: () => {
291
- throw new Error("No organisation context");
292
- },
293
- isOrganisationSecure: () => false,
294
- getPrimaryOrganisation: () => null
295
- };
296
- }
297
- return {
298
- selectedOrganisation,
299
- organisations,
300
- userMemberships,
301
- isLoading,
302
- error,
303
- hasValidOrganisationContext,
304
- setSelectedOrganisation,
305
- switchOrganisation,
306
- getUserRole,
307
- validateOrganisationAccess,
308
- refreshOrganisations,
309
- ensureOrganisationContext,
310
- isOrganisationSecure,
311
- getPrimaryOrganisation
312
- };
313
- }, [
314
- selectedOrganisation,
315
- organisations,
316
- userMemberships,
317
- isLoading,
318
- error,
319
- hasValidOrganisationContext,
320
- switchOrganisation,
321
- getUserRole,
322
- validateOrganisationAccess,
323
- refreshOrganisations,
324
- ensureOrganisationContext,
325
- isOrganisationSecure,
326
- getPrimaryOrganisation
327
- ]);
328
- if (isLoading || selectedOrganisation && !isContextReady) {
329
- return /* @__PURE__ */ jsx("div", { className: "organisation-loading", role: "status", "aria-label": "Loading organisation context", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
330
- /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4" }),
331
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: isLoading ? "Loading organisation context..." : "Setting up organisation context..." })
332
- ] }) }) });
333
- }
334
- if (error || user && !selectedOrganisation) {
335
- return /* @__PURE__ */ jsx("div", { className: "organisation-error", role: "alert", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md mx-auto p-6", children: [
336
- /* @__PURE__ */ jsx("div", { className: "text-destructive mb-4", children: /* @__PURE__ */ jsx("svg", { className: "h-12 w-12 mx-auto", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z" }) }) }),
337
- /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-foreground mb-2", children: "Organisation Access Required" }),
338
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mb-4", children: error?.message || "No valid organisation context available. Please contact your administrator to be added to an organisation." }),
339
- /* @__PURE__ */ jsx(
340
- "button",
341
- {
342
- onClick: handleLogoutAndRedirect,
343
- className: "px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90",
344
- children: "Sign Out"
345
- }
346
- )
347
- ] }) }) });
348
- }
349
- return /* @__PURE__ */ jsx(OrganisationContext.Provider, { value: contextValue, children });
350
- }
351
- var OrganisationContext, STORAGE_KEYS, useOrganisations;
352
- var init_OrganisationProvider = __esm({
353
- "src/providers/OrganisationProvider.tsx"() {
354
- "use strict";
355
- init_UnifiedAuthProvider();
356
- init_organisationContext();
357
- init_debugLogger();
358
- OrganisationContext = createContext(void 0);
359
- STORAGE_KEYS = {
360
- SELECTED_ORGANISATION: "pace-core-selected-organisation",
361
- ORGANISATION_CONTEXT: "pace-core-organisation-context"
362
- };
363
- useOrganisations = () => {
364
- const context = useContext(OrganisationContext);
365
- if (!context) {
366
- throw new Error("useOrganisations must be used within an OrganisationProvider");
367
- }
368
- return context;
369
- };
370
- }
371
- });
372
-
373
- export {
374
- OrganisationProvider,
375
- useOrganisations,
376
- OrganisationProvider_exports,
377
- init_OrganisationProvider
378
- };
379
- //# sourceMappingURL=chunk-COBPIXXQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/OrganisationProvider.tsx"],"sourcesContent":["/**\n * @file Organisation Provider\n * @package @jmruthers/pace-core\n * @module Providers/Organisation\n * @since 0.4.0\n *\n * Security-first organisation provider that enforces mandatory organisation context.\n * No data operations can proceed without valid organisation context.\n * \n * Features:\n * - Mandatory organisation selection for all operations\n * - User organisation membership validation\n * - Role-based access within organisations\n * - Secure organisation switching\n * - Hierarchy support for parent/child organisations\n * - Error handling for security violations\n * - Persistent organisation selection\n *\n * @example\n * ```tsx\n * // Basic setup - organisation context is mandatory\n * import { UnifiedAuthProvider, OrganisationProvider } from '@jmruthers/pace-core';\n * \n * function App() {\n * return (\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"MY_APP\">\n * <OrganisationProvider>\n * <YourAppContent />\n * </OrganisationProvider>\n * </UnifiedAuthProvider>\n * );\n * }\n * \n * // Using in components\n * function MyComponent() {\n * const { \n * selectedOrganisation, \n * getUserRole, \n * switchOrganisation \n * } = useOrganisations();\n * \n * // selectedOrganisation is guaranteed to be non-null when this renders\n * return (\n * <div>\n * <h1>{selectedOrganisation.display_name}</h1>\n * <p>Your role: {getUserRole()}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @security\n * - All data access requires valid organisation context\n * - User membership validation on organisation load\n * - Role-based access control within organisations\n * - Secure organisation switching with validation\n * - Error states for security violations\n * - No fallback to default organisation - explicit selection required\n *\n * @dependencies\n * - React 18+ - Context, hooks, and effects\n * - UnifiedAuthProvider - Authentication context\n * - Supabase - Database operations\n * - Organisation types - Type definitions\n */\n\nimport React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useUnifiedAuth } from './UnifiedAuthProvider';\nimport { setOrganisationContext } from '../utils/organisationContext';\nimport { DebugLogger } from '../utils/debugLogger';\nimport type {\n Organisation,\n OrganisationMembership,\n OrganisationContextType,\n OrganisationProviderProps,\n OrganisationSecurityError,\n OrganisationHierarchy\n} from '../types/organisation';\n\n// Create the context\nconst OrganisationContext = createContext<OrganisationContextType | undefined>(undefined);\n\n// Storage keys for persistence\nconst STORAGE_KEYS = {\n SELECTED_ORGANISATION: 'pace-core-selected-organisation',\n ORGANISATION_CONTEXT: 'pace-core-organisation-context',\n} as const;\n\n/**\n * Organisation Provider component that enforces mandatory organisation context\n * \n * This provider:\n * - Loads user's organisation memberships on authentication\n * - Validates user has at least one active organisation\n * - Auto-selects primary organisation or first available\n * - Provides security helpers for organisation validation\n * - Handles organisation switching with validation\n * - Persists organisation selection across sessions\n * \n * SECURITY: No children are rendered without valid organisation context\n */\nexport function OrganisationProvider({ children }: OrganisationProviderProps) {\n const [selectedOrganisation, setSelectedOrganisation] = useState<Organisation | null>(null);\n const [organisations, setOrganisations] = useState<Organisation[]>([]);\n const [userMemberships, setUserMemberships] = useState<OrganisationMembership[]>([]);\n const [roleMapState, setRoleMapState] = useState<Map<string, string>>(new Map());\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [isContextReady, setIsContextReady] = useState(false);\n \n const { user, session, supabase, signOut } = useUnifiedAuth();\n \n // Use navigate hook conditionally to avoid test failures\n let navigate: any = null;\n try {\n navigate = useNavigate();\n } catch (error) {\n // In test environment or when no router context, navigate will be null\n navigate = null;\n }\n\n // Set organisation context in database session\n const setDatabaseOrganisationContext = useCallback(async (organisation: Organisation): Promise<void> => {\n if (!supabase || !session) {\n console.warn('[OrganisationProvider] No Supabase client or session available for setting organisation context');\n setIsContextReady(false);\n return;\n }\n\n try {\n await setOrganisationContext(supabase, organisation.id);\n DebugLogger.log('OrganisationProvider', 'Database organisation context set to:', organisation.display_name);\n setIsContextReady(true);\n } catch (error) {\n console.error('[OrganisationProvider] Failed to set database organisation context:', error);\n setIsContextReady(false);\n // Don't throw - this is a non-critical operation\n }\n }, [supabase, session]);\n\n // CRITICAL: Set database organisation context when organisation changes\n useEffect(() => {\n if (selectedOrganisation && supabase && session) {\n // Reset context ready state when organisation changes\n setIsContextReady(false);\n \n // Use an async IIFE to properly handle the async operation\n (async () => {\n await setDatabaseOrganisationContext(selectedOrganisation);\n })();\n } else {\n setIsContextReady(false);\n }\n }, [selectedOrganisation, setDatabaseOrganisationContext, supabase, session]);\n\n // CRITICAL: Load user organisations and validate access\n const loadUserOrganisations = useCallback(async () => {\n if (!user || !session || !supabase) {\n // Clear state when no user, session, or supabase client\n DebugLogger.log('OrganisationProvider', 'Clearing organisation state - no user, session, or supabase client');\n setSelectedOrganisation(null);\n setOrganisations([]);\n setUserMemberships([]);\n setIsLoading(false);\n setError(null);\n return;\n }\n setIsLoading(true);\n setError(null);\n \n try {\n DebugLogger.log(\"OrganisationProvider\", \"Loading organisations for user:\", user.id);\n \n // Get user's organisation memberships from consolidated rbac_organisation_roles table\n // Only get actual members (org_admin, leader, member) - exclude supporters\n let memberships, membershipError;\n try {\n const result = await supabase\n .from('rbac_organisation_roles')\n .select(`\n id,\n user_id,\n organisation_id,\n role,\n status,\n granted_at,\n granted_by,\n revoked_at,\n revoked_by,\n notes,\n created_at,\n updated_at\n `)\n .eq('user_id', user.id)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']); // Only actual members, not supporters\n \n memberships = result.data;\n membershipError = result.error;\n } catch (queryError: any) {\n membershipError = queryError;\n }\n\n if (membershipError) {\n console.error(\"[OrganisationProvider] Error loading memberships:\", membershipError);\n throw membershipError;\n }\n \n DebugLogger.log(\"OrganisationProvider\", \"Raw memberships data:\", memberships);\n \n if (!memberships || memberships.length === 0) {\n throw new Error('User has no active organisation memberships') as OrganisationSecurityError;\n }\n\n // Get organisation details for the memberships\n const organisationIds = memberships.map((m: any) => m.organisation_id);\n const { data: organisations, error: orgError } = await supabase\n .from('organisations')\n .select('id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at')\n .in('id', organisationIds);\n\n if (orgError) {\n console.error(\"[OrganisationProvider] Error loading organisations:\", orgError);\n throw orgError;\n }\n\n // Create a map of organisation_id to role from the memberships data\n // Since we're now getting roles directly from the consolidated table\n const roleMap = new Map<string, string>();\n memberships?.forEach((membership: any) => {\n roleMap.set(membership.organisation_id, membership.role);\n });\n\n // Extract organisations and memberships\n const orgs = organisations as Organisation[];\n const activeOrgs = orgs.filter(org => org.is_active);\n \n if (activeOrgs.length === 0) {\n throw new Error('User has no access to active organisations') as OrganisationSecurityError;\n }\n\n DebugLogger.log(\"OrganisationProvider\", \"Active organisations:\", activeOrgs);\n \n setOrganisations(activeOrgs);\n setUserMemberships(memberships as OrganisationMembership[]);\n \n // Store role map in component state for later use\n setRoleMapState(roleMap);\n \n // Auto-select organisation: try persisted, then primary, then first\n let initialOrg: Organisation | null = null;\n \n // 1. Try to restore from localStorage\n try {\n const persistedOrgString = localStorage.getItem(STORAGE_KEYS.SELECTED_ORGANISATION);\n if (persistedOrgString) {\n const persistedOrg = JSON.parse(persistedOrgString) as Organisation;\n const validPersistedOrg = activeOrgs.find(org => org.id === persistedOrg.id);\n if (validPersistedOrg) {\n initialOrg = validPersistedOrg;\n DebugLogger.log(\"OrganisationProvider\", \"Restored persisted organisation:\", initialOrg.display_name);\n }\n }\n } catch (storageError) {\n console.warn(\"[OrganisationProvider] Failed to restore persisted organisation:\", storageError);\n }\n \n // 2. Fall back to org_admin role organisation (highest privilege)\n if (!initialOrg) {\n const adminMembership = memberships.find((m: any) => m.role === 'org_admin');\n if (adminMembership) {\n const foundOrg = organisations.find((org: any) => org.id === adminMembership.organisation_id);\n if (foundOrg) {\n initialOrg = foundOrg;\n DebugLogger.log(\"OrganisationProvider\", \"Selected org_admin organisation:\", initialOrg.display_name);\n }\n }\n }\n \n // 3. Fall back to first organisation\n if (!initialOrg) {\n initialOrg = activeOrgs[0];\n DebugLogger.log(\"OrganisationProvider\", \"Selected first organisation:\", initialOrg.display_name);\n }\n \n if (!initialOrg) {\n throw new Error('No valid organisation found for user') as OrganisationSecurityError;\n }\n\n setSelectedOrganisation(initialOrg);\n \n // Persist selection\n localStorage.setItem(STORAGE_KEYS.SELECTED_ORGANISATION, JSON.stringify(initialOrg));\n \n DebugLogger.log(\"OrganisationProvider\", \"Organisation context established:\", {\n selectedOrganisation: initialOrg.display_name,\n totalOrganisations: activeOrgs.length,\n userRole: roleMap.get(initialOrg.id)\n });\n \n } catch (err) {\n console.error(\"[OrganisationProvider] Failed to load organisations:\", err);\n setError(err as Error);\n // SECURITY: Clear all state on error\n setSelectedOrganisation(null);\n setOrganisations([]);\n setUserMemberships([]);\n localStorage.removeItem(STORAGE_KEYS.SELECTED_ORGANISATION);\n } finally {\n setIsLoading(false);\n }\n }, [user, session, supabase]);\n\n // Load organisations when dependencies change\n useEffect(() => {\n loadUserOrganisations();\n }, [loadUserOrganisations]);\n\n // Handle logout and redirect to login\n const handleLogoutAndRedirect = useCallback(async () => {\n try {\n await signOut();\n if (navigate) {\n navigate('/login', { replace: true });\n } else {\n // Fallback to window.location if navigate is not available\n window.location.href = '/login';\n }\n } catch (error) {\n console.error('[OrganisationProvider] Error during logout:', error);\n // Even if logout fails, redirect to login\n if (navigate) {\n navigate('/login', { replace: true });\n } else {\n // Fallback to window.location if navigate is not available\n window.location.href = '/login';\n }\n }\n }, [signOut, navigate]);\n\n // Security validation helper\n const ensureOrganisationContext = useCallback((): Organisation => {\n if (!selectedOrganisation) {\n throw new Error('Organisation context is required but not available') as OrganisationSecurityError;\n }\n return selectedOrganisation;\n }, [selectedOrganisation]);\n\n // Get user's role in specified organisation (defaults to current)\n const getUserRole = useCallback((orgId?: string): string => {\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return 'no_access';\n \n // Use roleMapState to get the role for this organisation\n return roleMapState.get(targetOrgId) || 'no_access';\n }, [roleMapState, selectedOrganisation]);\n\n // Validate user has access to organisation\n const validateOrganisationAccess = useCallback((orgId: string): boolean => {\n return userMemberships.some((m: any) => \n m.organisation_id === orgId && \n m.status === 'active' &&\n m.revoked_at === null\n );\n }, [userMemberships]);\n\n // Secure organisation switching\n const switchOrganisation = useCallback(async (orgId: string): Promise<void> => {\n DebugLogger.log(\"OrganisationProvider\", \"Switching to organisation:\", orgId);\n \n // Validate access\n if (!validateOrganisationAccess(orgId)) {\n throw new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n }\n \n const targetOrg = organisations.find(org => org.id === orgId);\n if (!targetOrg) {\n throw new Error(`Organisation ${orgId} not found in user's organisations`) as OrganisationSecurityError;\n }\n \n setSelectedOrganisation(targetOrg);\n \n // Persist selection\n localStorage.setItem(STORAGE_KEYS.SELECTED_ORGANISATION, JSON.stringify(targetOrg));\n \n // Set database organisation context\n await setDatabaseOrganisationContext(targetOrg);\n \n DebugLogger.log(\"OrganisationProvider\", \"Switched to organisation:\", targetOrg.display_name);\n }, [organisations, validateOrganisationAccess, setDatabaseOrganisationContext]);\n\n // Refresh organisations data\n const refreshOrganisations = useCallback(async (): Promise<void> => {\n if (!user || !session || !supabase) return;\n \n // Force reload by triggering the effect\n setIsLoading(true);\n // The useEffect will handle the actual reload\n }, [user, session, supabase]);\n\n // Get primary organisation (highest privilege role)\n const getPrimaryOrganisation = useCallback((): Organisation | null => {\n // Look for org_admin role first, then leader, then member\n const rolePriority = ['org_admin', 'leader', 'member'];\n \n for (const role of rolePriority) {\n const membership = userMemberships.find((m: any) => m.role === role);\n if (membership) {\n return organisations.find((org: any) => org.id === membership.organisation_id) || null;\n }\n }\n \n return null;\n }, [userMemberships, organisations]);\n\n // Security status\n const isOrganisationSecure = useCallback((): boolean => {\n return !!(selectedOrganisation && user);\n }, [selectedOrganisation, user]);\n\n // Build organisation hierarchy (for future use)\n const buildOrganisationHierarchy = useCallback((orgs: Organisation[]): OrganisationHierarchy[] => {\n const orgMap = new Map<string, Organisation>();\n orgs.forEach(org => orgMap.set(org.id, org));\n \n const roots: OrganisationHierarchy[] = [];\n \n orgs.forEach(org => {\n if (!org.parent_id) {\n // Root organisation\n roots.push({\n organisation: org,\n children: [],\n depth: 0\n });\n }\n });\n \n // For now, return flat structure - hierarchy building can be added later\n return roots;\n }, []);\n\n // Computed values\n const hasValidOrganisationContext = useMemo(() => {\n return !!(selectedOrganisation && !isLoading && !error && isContextReady);\n }, [selectedOrganisation, isLoading, error, isContextReady]);\n\n // Memoized context value\n const contextValue = useMemo<OrganisationContextType>(() => {\n // SECURITY: Only provide full context if we have valid organisation\n if (!selectedOrganisation) {\n // This will never be accessed due to the render guards above,\n // but TypeScript requires the interface to be satisfied\n const placeholderOrg: Organisation = {\n id: '',\n name: '',\n display_name: '',\n subscription_tier: 'standard',\n settings: {},\n is_active: false,\n created_at: '',\n updated_at: ''\n };\n \n return {\n selectedOrganisation: placeholderOrg,\n organisations: [],\n userMemberships: [],\n isLoading,\n error,\n hasValidOrganisationContext: false,\n setSelectedOrganisation: () => {},\n switchOrganisation: async () => {},\n getUserRole: () => 'no_access',\n validateOrganisationAccess: () => false,\n refreshOrganisations: async () => {},\n ensureOrganisationContext: () => { throw new Error('No organisation context') as OrganisationSecurityError; },\n isOrganisationSecure: () => false,\n getPrimaryOrganisation: () => null\n };\n }\n\n return {\n selectedOrganisation,\n organisations,\n userMemberships,\n isLoading,\n error,\n hasValidOrganisationContext,\n setSelectedOrganisation,\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations,\n ensureOrganisationContext,\n isOrganisationSecure,\n getPrimaryOrganisation\n };\n }, [\n selectedOrganisation,\n organisations,\n userMemberships,\n isLoading,\n error,\n hasValidOrganisationContext,\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations,\n ensureOrganisationContext,\n isOrganisationSecure,\n getPrimaryOrganisation\n ]);\n\n // SECURITY: Only render children when we have valid organisation context\n if (isLoading || (selectedOrganisation && !isContextReady)) {\n return (\n <div className=\"organisation-loading\" role=\"status\" aria-label=\"Loading organisation context\">\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center\">\n <div className=\"animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4\"></div>\n <p className=\"text-muted-foreground\">\n {isLoading ? 'Loading organisation context...' : 'Setting up organisation context...'}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (error || (user && !selectedOrganisation)) {\n return (\n <div className=\"organisation-error\" role=\"alert\">\n <div className=\"flex items-center justify-center min-h-screen\">\n <div className=\"text-center max-w-md mx-auto p-6\">\n <div className=\"text-destructive mb-4\">\n <svg className=\"h-12 w-12 mx-auto\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.732-.833-2.464 0L4.35 16.5c-.77.833.192 2.5 1.732 2.5z\" />\n </svg>\n </div>\n <h2 className=\"text-xl font-semibold text-foreground mb-2\">\n Organisation Access Required\n </h2>\n <p className=\"text-muted-foreground mb-4\">\n {error?.message || 'No valid organisation context available. Please contact your administrator to be added to an organisation.'}\n </p>\n <button \n onClick={handleLogoutAndRedirect}\n className=\"px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90\"\n >\n Sign Out\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <OrganisationContext.Provider value={contextValue}>\n {children}\n </OrganisationContext.Provider>\n );\n}\n\n/**\n * Hook to access organisation context\n * \n * @returns Organisation context with guaranteed non-null selectedOrganisation\n * @throws {Error} If used outside OrganisationProvider\n */\nexport const useOrganisations = (): OrganisationContextType => {\n const context = useContext(OrganisationContext);\n if (!context) {\n throw new Error('useOrganisations must be used within an OrganisationProvider');\n }\n return context;\n};\n\n// Re-export types for convenience\nexport type { \n Organisation, \n OrganisationMembership, \n OrganisationContextType,\n OrganisationSecurityError\n}; "],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkEA,SAAgB,eAAe,YAAY,UAAU,WAAW,aAAa,eAAe;AAC5F,SAAS,mBAAmB;AAsclB,SACE,KADF;AAnaH,SAAS,qBAAqB,EAAE,SAAS,GAA8B;AAC5E,QAAM,CAAC,sBAAsB,uBAAuB,IAAI,SAA8B,IAAI;AAC1F,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAyB,CAAC,CAAC;AACrE,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,SAAmC,CAAC,CAAC;AACnF,QAAM,CAAC,cAAc,eAAe,IAAI,SAA8B,oBAAI,IAAI,CAAC;AAC/E,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AACrD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,KAAK;AAE1D,QAAM,EAAE,MAAM,SAAS,UAAU,QAAQ,IAAI,eAAe;AAG5D,MAAI,WAAgB;AACpB,MAAI;AACF,eAAW,YAAY;AAAA,EACzB,SAASA,QAAO;AAEd,eAAW;AAAA,EACb;AAGA,QAAM,iCAAiC,YAAY,OAAO,iBAA8C;AACtG,QAAI,CAAC,YAAY,CAAC,SAAS;AACzB,cAAQ,KAAK,iGAAiG;AAC9G,wBAAkB,KAAK;AACvB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,uBAAuB,UAAU,aAAa,EAAE;AACtD,kBAAY,IAAI,wBAAwB,yCAAyC,aAAa,YAAY;AAC1G,wBAAkB,IAAI;AAAA,IACxB,SAASA,QAAO;AACd,cAAQ,MAAM,uEAAuEA,MAAK;AAC1F,wBAAkB,KAAK;AAAA,IAEzB;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,CAAC;AAGtB,YAAU,MAAM;AACd,QAAI,wBAAwB,YAAY,SAAS;AAE/C,wBAAkB,KAAK;AAGvB,OAAC,YAAY;AACX,cAAM,+BAA+B,oBAAoB;AAAA,MAC3D,GAAG;AAAA,IACL,OAAO;AACL,wBAAkB,KAAK;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,sBAAsB,gCAAgC,UAAU,OAAO,CAAC;AAG5E,QAAM,wBAAwB,YAAY,YAAY;AACpD,QAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU;AAElC,kBAAY,IAAI,wBAAwB,oEAAoE;AAC5G,8BAAwB,IAAI;AAC5B,uBAAiB,CAAC,CAAC;AACnB,yBAAmB,CAAC,CAAC;AACrB,mBAAa,KAAK;AAClB,eAAS,IAAI;AACb;AAAA,IACF;AACE,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,QAAI;AACF,kBAAY,IAAI,wBAAwB,mCAAmC,KAAK,EAAE;AAIlF,UAAI,aAAa;AACjB,UAAI;AACF,cAAM,SAAS,MAAM,SAClB,KAAK,yBAAyB,EAC9B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAaP,EACA,GAAG,WAAW,KAAK,EAAE,EACrB,GAAG,UAAU,QAAQ,EACrB,GAAG,cAAc,IAAI,EACrB,GAAG,QAAQ,CAAC,aAAa,UAAU,QAAQ,CAAC;AAE/C,sBAAc,OAAO;AACrB,0BAAkB,OAAO;AAAA,MAC3B,SAAS,YAAiB;AACxB,0BAAkB;AAAA,MACpB;AAEA,UAAI,iBAAiB;AACnB,gBAAQ,MAAM,qDAAqD,eAAe;AAClF,cAAM;AAAA,MACR;AAEA,kBAAY,IAAI,wBAAwB,yBAAyB,WAAW;AAE5E,UAAI,CAAC,eAAe,YAAY,WAAW,GAAG;AAC5C,cAAM,IAAI,MAAM,6CAA6C;AAAA,MAC/D;AAGA,YAAM,kBAAkB,YAAY,IAAI,CAAC,MAAW,EAAE,eAAe;AACrE,YAAM,EAAE,MAAMC,gBAAe,OAAO,SAAS,IAAI,MAAM,SACpD,KAAK,eAAe,EACpB,OAAO,mGAAmG,EAC1G,GAAG,MAAM,eAAe;AAE3B,UAAI,UAAU;AACZ,gBAAQ,MAAM,uDAAuD,QAAQ;AAC7E,cAAM;AAAA,MACR;AAIA,YAAM,UAAU,oBAAI,IAAoB;AACxC,mBAAa,QAAQ,CAAC,eAAoB;AACxC,gBAAQ,IAAI,WAAW,iBAAiB,WAAW,IAAI;AAAA,MACzD,CAAC;AAGD,YAAM,OAAOA;AACb,YAAM,aAAa,KAAK,OAAO,SAAO,IAAI,SAAS;AAEnD,UAAI,WAAW,WAAW,GAAG;AAC3B,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,kBAAY,IAAI,wBAAwB,yBAAyB,UAAU;AAE3E,uBAAiB,UAAU;AAC3B,yBAAmB,WAAuC;AAG1D,sBAAgB,OAAO;AAGvB,UAAI,aAAkC;AAGtC,UAAI;AACF,cAAM,qBAAqB,aAAa,QAAQ,aAAa,qBAAqB;AAClF,YAAI,oBAAoB;AACtB,gBAAM,eAAe,KAAK,MAAM,kBAAkB;AAClD,gBAAM,oBAAoB,WAAW,KAAK,SAAO,IAAI,OAAO,aAAa,EAAE;AAC3E,cAAI,mBAAmB;AACrB,yBAAa;AACb,wBAAY,IAAI,wBAAwB,oCAAoC,WAAW,YAAY;AAAA,UACrG;AAAA,QACF;AAAA,MACF,SAAS,cAAc;AACrB,gBAAQ,KAAK,oEAAoE,YAAY;AAAA,MAC/F;AAGA,UAAI,CAAC,YAAY;AACf,cAAM,kBAAkB,YAAY,KAAK,CAAC,MAAW,EAAE,SAAS,WAAW;AAC3E,YAAI,iBAAiB;AACnB,gBAAM,WAAWA,eAAc,KAAK,CAAC,QAAa,IAAI,OAAO,gBAAgB,eAAe;AAC5F,cAAI,UAAU;AACZ,yBAAa;AACb,wBAAY,IAAI,wBAAwB,oCAAoC,WAAW,YAAY;AAAA,UACrG;AAAA,QACF;AAAA,MACF;AAGA,UAAI,CAAC,YAAY;AACf,qBAAa,WAAW,CAAC;AACzB,oBAAY,IAAI,wBAAwB,gCAAgC,WAAW,YAAY;AAAA,MACjG;AAEA,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AAEA,8BAAwB,UAAU;AAGlC,mBAAa,QAAQ,aAAa,uBAAuB,KAAK,UAAU,UAAU,CAAC;AAEnF,kBAAY,IAAI,wBAAwB,qCAAqC;AAAA,QAC3E,sBAAsB,WAAW;AAAA,QACjC,oBAAoB,WAAW;AAAA,QAC/B,UAAU,QAAQ,IAAI,WAAW,EAAE;AAAA,MACrC,CAAC;AAAA,IAEH,SAAS,KAAK;AACZ,cAAQ,MAAM,wDAAwD,GAAG;AACzE,eAAS,GAAY;AAErB,8BAAwB,IAAI;AAC5B,uBAAiB,CAAC,CAAC;AACnB,yBAAmB,CAAC,CAAC;AACrB,mBAAa,WAAW,aAAa,qBAAqB;AAAA,IAC5D,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACJ,GAAG,CAAC,MAAM,SAAS,QAAQ,CAAC;AAG5B,YAAU,MAAM;AACd,0BAAsB;AAAA,EACxB,GAAG,CAAC,qBAAqB,CAAC;AAG1B,QAAM,0BAA0B,YAAY,YAAY;AACtD,QAAI;AACF,YAAM,QAAQ;AACd,UAAI,UAAU;AACZ,iBAAS,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,MACtC,OAAO;AAEL,eAAO,SAAS,OAAO;AAAA,MACzB;AAAA,IACF,SAASD,QAAO;AACd,cAAQ,MAAM,+CAA+CA,MAAK;AAElE,UAAI,UAAU;AACZ,iBAAS,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,MACtC,OAAO;AAEL,eAAO,SAAS,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,CAAC;AAGtB,QAAM,4BAA4B,YAAY,MAAoB;AAChE,QAAI,CAAC,sBAAsB;AACzB,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,WAAO;AAAA,EACT,GAAG,CAAC,oBAAoB,CAAC;AAGzB,QAAM,cAAc,YAAY,CAAC,UAA2B;AAC1D,UAAM,cAAc,SAAS,sBAAsB;AACnD,QAAI,CAAC,YAAa,QAAO;AAGzB,WAAO,aAAa,IAAI,WAAW,KAAK;AAAA,EAC1C,GAAG,CAAC,cAAc,oBAAoB,CAAC;AAGvC,QAAM,6BAA6B,YAAY,CAAC,UAA2B;AACzE,WAAO,gBAAgB;AAAA,MAAK,CAAC,MAC3B,EAAE,oBAAoB,SACtB,EAAE,WAAW,YACb,EAAE,eAAe;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,qBAAqB,YAAY,OAAO,UAAiC;AAC7E,gBAAY,IAAI,wBAAwB,8BAA8B,KAAK;AAG3E,QAAI,CAAC,2BAA2B,KAAK,GAAG;AACtC,YAAM,IAAI,MAAM,6CAA6C,KAAK,EAAE;AAAA,IACtE;AAEA,UAAM,YAAY,cAAc,KAAK,SAAO,IAAI,OAAO,KAAK;AAC5D,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,gBAAgB,KAAK,oCAAoC;AAAA,IAC3E;AAEA,4BAAwB,SAAS;AAGjC,iBAAa,QAAQ,aAAa,uBAAuB,KAAK,UAAU,SAAS,CAAC;AAGlF,UAAM,+BAA+B,SAAS;AAE9C,gBAAY,IAAI,wBAAwB,6BAA6B,UAAU,YAAY;AAAA,EAC7F,GAAG,CAAC,eAAe,4BAA4B,8BAA8B,CAAC;AAG9E,QAAM,uBAAuB,YAAY,YAA2B;AAClE,QAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,SAAU;AAGpC,iBAAa,IAAI;AAAA,EAEnB,GAAG,CAAC,MAAM,SAAS,QAAQ,CAAC;AAG5B,QAAM,yBAAyB,YAAY,MAA2B;AAEpE,UAAM,eAAe,CAAC,aAAa,UAAU,QAAQ;AAErD,eAAW,QAAQ,cAAc;AAC/B,YAAM,aAAa,gBAAgB,KAAK,CAAC,MAAW,EAAE,SAAS,IAAI;AACnE,UAAI,YAAY;AACd,eAAO,cAAc,KAAK,CAAC,QAAa,IAAI,OAAO,WAAW,eAAe,KAAK;AAAA,MACpF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,aAAa,CAAC;AAGnC,QAAM,uBAAuB,YAAY,MAAe;AACtD,WAAO,CAAC,EAAE,wBAAwB;AAAA,EACpC,GAAG,CAAC,sBAAsB,IAAI,CAAC;AAG/B,QAAM,6BAA6B,YAAY,CAAC,SAAkD;AAChG,UAAM,SAAS,oBAAI,IAA0B;AAC7C,SAAK,QAAQ,SAAO,OAAO,IAAI,IAAI,IAAI,GAAG,CAAC;AAE3C,UAAM,QAAiC,CAAC;AAExC,SAAK,QAAQ,SAAO;AAClB,UAAI,CAAC,IAAI,WAAW;AAElB,cAAM,KAAK;AAAA,UACT,cAAc;AAAA,UACd,UAAU,CAAC;AAAA,UACX,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAGD,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAGL,QAAM,8BAA8B,QAAQ,MAAM;AAChD,WAAO,CAAC,EAAE,wBAAwB,CAAC,aAAa,CAAC,SAAS;AAAA,EAC5D,GAAG,CAAC,sBAAsB,WAAW,OAAO,cAAc,CAAC;AAG3D,QAAM,eAAe,QAAiC,MAAM;AAE1D,QAAI,CAAC,sBAAsB;AAGzB,YAAM,iBAA+B;AAAA,QACnC,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,cAAc;AAAA,QACd,mBAAmB;AAAA,QACnB,UAAU,CAAC;AAAA,QACX,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAEA,aAAO;AAAA,QACL,sBAAsB;AAAA,QACtB,eAAe,CAAC;AAAA,QAChB,iBAAiB,CAAC;AAAA,QAClB;AAAA,QACA;AAAA,QACA,6BAA6B;AAAA,QAC7B,yBAAyB,MAAM;AAAA,QAAC;AAAA,QAChC,oBAAoB,YAAY;AAAA,QAAC;AAAA,QACjC,aAAa,MAAM;AAAA,QACnB,4BAA4B,MAAM;AAAA,QAClC,sBAAsB,YAAY;AAAA,QAAC;AAAA,QACnC,2BAA2B,MAAM;AAAE,gBAAM,IAAI,MAAM,yBAAyB;AAAA,QAAgC;AAAA,QAC5G,sBAAsB,MAAM;AAAA,QAC5B,wBAAwB,MAAM;AAAA,MAChC;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,MAAI,aAAc,wBAAwB,CAAC,gBAAiB;AAC1D,WACE,oBAAC,SAAI,WAAU,wBAAuB,MAAK,UAAS,cAAW,gCAC7D,8BAAC,SAAI,WAAU,iDACb,+BAAC,SAAI,WAAU,eACb;AAAA,0BAAC,SAAI,WAAU,4EAA2E;AAAA,MAC1F,oBAAC,OAAE,WAAU,yBACV,sBAAY,oCAAoC,sCACnD;AAAA,OACF,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,SAAU,QAAQ,CAAC,sBAAuB;AAC5C,WACE,oBAAC,SAAI,WAAU,sBAAqB,MAAK,SACvC,8BAAC,SAAI,WAAU,iDACb,+BAAC,SAAI,WAAU,oCACb;AAAA,0BAAC,SAAI,WAAU,yBACb,8BAAC,SAAI,WAAU,qBAAoB,MAAK,QAAO,SAAQ,aAAY,QAAO,gBACxE,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,aAAa,GAAG,GAAE,4IAA2I,GAClN,GACF;AAAA,MACA,oBAAC,QAAG,WAAU,8CAA6C,0CAE3D;AAAA,MACA,oBAAC,OAAE,WAAU,8BACV,iBAAO,WAAW,8GACrB;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OACF,GACF,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,oBAAoB,UAApB,EAA6B,OAAO,cAClC,UACH;AAEJ;AArjBA,IAiFM,qBAGA,cAyeO;AA7jBb;AAAA;AAAA;AAoEA;AACA;AACA;AAWA,IAAM,sBAAsB,cAAmD,MAAS;AAGxF,IAAM,eAAe;AAAA,MACnB,uBAAuB;AAAA,MACvB,sBAAsB;AAAA,IACxB;AAseO,IAAM,mBAAmB,MAA+B;AAC7D,YAAM,UAAU,WAAW,mBAAmB;AAC9C,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,8DAA8D;AAAA,MAChF;AACA,aAAO;AAAA,IACT;AAAA;AAAA;","names":["error","organisations"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/organisationContext.ts"],"sourcesContent":["/**\n * @file Organisation Context Utility\n * @package @jmruthers/pace-core\n * @module Utils/OrganisationContext\n * @since 0.4.0\n *\n * Utility functions for managing organisation context in database sessions.\n * Provides fallback mechanisms for when database functions are not available.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\n\n/**\n * Set organisation context in the database session\n * \n * This function attempts to set the organisation context using a database function.\n * If the function is not available, it falls back gracefully without throwing errors.\n * \n * @param supabase - Supabase client instance\n * @param organisationId - The organisation ID to set as context\n * @returns Promise that resolves when context is set (or falls back gracefully)\n */\nexport async function setOrganisationContext(\n supabase: SupabaseClient,\n organisationId: string\n): Promise<void> {\n if (!supabase || !organisationId) {\n // TODO: Replace with proper logging service integration\n return;\n }\n\n try {\n // Try to call the database function to set organisation context\n const { error } = await supabase.rpc('set_organisation_context', {\n org_id: organisationId\n });\n\n if (error) {\n // Function might not exist yet - this is expected during migration\n // Silent fail - will fall back to client-side filtering\n // TODO: Replace with proper logging service integration\n } else {\n // TODO: Replace with proper logging service integration\n }\n } catch (error) {\n // Handle any other errors gracefully\n // Silent fail - will fall back to client-side filtering\n // TODO: Replace with proper logging service integration\n }\n}\n\n/**\n * Clear organisation context from the database session\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves when context is cleared\n */\nexport async function clearOrganisationContext(\n supabase: SupabaseClient\n): Promise<void> {\n if (!supabase) {\n // TODO: Replace with proper logging service integration\n return;\n }\n\n try {\n const { error } = await supabase.rpc('clear_organisation_context');\n \n if (error) {\n // Silent fail - function not available\n // TODO: Replace with proper logging service integration\n } else {\n // TODO: Replace with proper logging service integration\n }\n } catch (error) {\n // Silent fail - error occurred\n // TODO: Replace with proper logging service integration\n }\n}\n\n/**\n * Get current organisation context from the database session\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves to the current organisation ID or null\n */\nexport async function getOrganisationContext(\n supabase: SupabaseClient\n): Promise<string | null> {\n if (!supabase) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n\n try {\n const { data, error } = await supabase.rpc('get_organisation_context');\n \n if (error) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n \n // TODO: Replace with proper logging service integration\n return data;\n } catch (error) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n}\n\n/**\n * Check if organisation context functions are available in the database\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves to true if functions are available\n */\nexport async function isOrganisationContextAvailable(\n supabase: SupabaseClient\n): Promise<boolean> {\n if (!supabase) {\n return false;\n }\n\n try {\n const { error } = await supabase.rpc('get_organisation_context');\n \n if (error) {\n return false;\n }\n \n return true;\n } catch (error) {\n return false;\n }\n} "],"mappings":";;;;;AAsBA,eAAsB,uBACpB,UACA,gBACe;AACf,MAAI,CAAC,YAAY,CAAC,gBAAgB;AAEhC;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,4BAA4B;AAAA,MAC/D,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,OAAO;AAAA,IAIX,OAAO;AAAA,IAEP;AAAA,EACF,SAAS,OAAO;AAAA,EAIhB;AACF;AAQA,eAAsB,yBACpB,UACe;AACf,MAAI,CAAC,UAAU;AAEb;AAAA,EACF;AAEA,MAAI;AACF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,4BAA4B;AAEjE,QAAI,OAAO;AAAA,IAGX,OAAO;AAAA,IAEP;AAAA,EACF,SAAS,OAAO;AAAA,EAGhB;AACF;AAQA,eAAsB,uBACpB,UACwB;AACxB,MAAI,CAAC,UAAU;AAEb,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAAS,IAAI,0BAA0B;AAErE,QAAI,OAAO;AAET,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT,SAAS,OAAO;AAEd,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,+BACpB,UACkB;AAClB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,0BAA0B;AAE/D,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAtIA;AAAA;AAAA;AAAA;AAAA;","names":[]}
@@ -1,62 +0,0 @@
1
- import {
2
- __esm
3
- } from "./chunk-PLDDJCW6.js";
4
-
5
- // src/utils/debugLogger.ts
6
- var DebugLogger;
7
- var init_debugLogger = __esm({
8
- "src/utils/debugLogger.ts"() {
9
- "use strict";
10
- DebugLogger = class {
11
- /**
12
- * Log debug information only in development mode
13
- */
14
- static log(component, message, ...args) {
15
- if (this.isDevelopment) {
16
- console.log(`[${component}] ${message}`, ...args);
17
- }
18
- }
19
- /**
20
- * Log error information (always logged)
21
- */
22
- static error(component, message, ...args) {
23
- console.error(`[${component}] ${message}`, ...args);
24
- }
25
- /**
26
- * Log warning information (always logged)
27
- */
28
- static warn(component, message, ...args) {
29
- console.warn(`[${component}] ${message}`, ...args);
30
- }
31
- /**
32
- * Log info information only in development mode
33
- */
34
- static info(component, message, ...args) {
35
- if (this.isDevelopment) {
36
- console.info(`[${component}] ${message}`, ...args);
37
- }
38
- }
39
- };
40
- DebugLogger.isDevelopment = false;
41
- }
42
- });
43
-
44
- // src/utils/cn.ts
45
- import { clsx } from "clsx";
46
- import { twMerge } from "tailwind-merge";
47
- function cn(...inputs) {
48
- return twMerge(clsx(inputs));
49
- }
50
- var init_cn = __esm({
51
- "src/utils/cn.ts"() {
52
- "use strict";
53
- }
54
- });
55
-
56
- export {
57
- DebugLogger,
58
- init_debugLogger,
59
- cn,
60
- init_cn
61
- };
62
- //# sourceMappingURL=chunk-OYRY44Q2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/debugLogger.ts","../src/utils/cn.ts"],"sourcesContent":["/**\n * @file Debug Logger Utility\n * @package @jmruthers/pace-core\n * @module Utils/DebugLogger\n * @since 0.4.76\n */\n\n/**\n * Debug logger that respects environment settings\n * Only logs in development mode to prevent production console spam\n */\nexport class DebugLogger {\n private static isDevelopment = process.env.NODE_ENV === 'development';\n\n /**\n * Log debug information only in development mode\n */\n static log(component: string, message: string, ...args: any[]): void {\n if (this.isDevelopment) {\n console.log(`[${component}] ${message}`, ...args);\n }\n }\n\n /**\n * Log error information (always logged)\n */\n static error(component: string, message: string, ...args: any[]): void {\n console.error(`[${component}] ${message}`, ...args);\n }\n\n /**\n * Log warning information (always logged)\n */\n static warn(component: string, message: string, ...args: any[]): void {\n console.warn(`[${component}] ${message}`, ...args);\n }\n\n /**\n * Log info information only in development mode\n */\n static info(component: string, message: string, ...args: any[]): void {\n if (this.isDevelopment) {\n console.info(`[${component}] ${message}`, ...args);\n }\n }\n}\n","\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}"],"mappings":";;;;;AAAA,IAWa;AAXb;AAAA;AAAA;AAWO,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA,MAMvB,OAAO,IAAI,WAAmB,YAAoB,MAAmB;AACnE,YAAI,KAAK,eAAe;AACtB,kBAAQ,IAAI,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,QAClD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,MAAM,WAAmB,YAAoB,MAAmB;AACrE,gBAAQ,MAAM,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,MACpD;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,KAAK,WAAmB,YAAoB,MAAmB;AACpE,gBAAQ,KAAK,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,MACnD;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,KAAK,WAAmB,YAAoB,MAAmB;AACpE,YAAI,KAAK,eAAe;AACtB,kBAAQ,KAAK,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAjCE,IADW,YACI,gBAAgB;AAAA;AAAA;;;ACXjC,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;AANA;AAAA;AAAA;AAAA;AAAA;","names":[]}