@jmruthers/pace-core 0.5.121 → 0.5.124

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 (255) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-OKDYRW2S.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  11. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  12. package/dist/{chunk-HFBOFZ3Z.js → chunk-GBGYYMC6.js} +317 -251
  13. package/dist/chunk-GBGYYMC6.js.map +1 -0
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-QPI2CCBA.js → chunk-VPUCTHTY.js} +149 -96
  23. package/dist/chunk-VPUCTHTY.js.map +1 -0
  24. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  25. package/dist/chunk-XN6GWKMV.js.map +1 -0
  26. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  27. package/dist/chunk-ZBLK676C.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +125 -144
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/DataTableToolbar.tsx +14 -1
  175. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  176. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  177. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  178. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  179. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  180. package/src/components/Dialog/Dialog.tsx +1 -1
  181. package/src/components/Dialog/README.md +24 -24
  182. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  183. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  184. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  185. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  186. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  187. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  188. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  189. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  190. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  191. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  192. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  193. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  194. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  195. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  196. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  197. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  198. package/src/examples/PublicEventPage.tsx +41 -41
  199. package/src/examples/PublicPageApp.tsx +33 -33
  200. package/src/examples/PublicPageUsageExample.tsx +30 -30
  201. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  202. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  203. package/src/hooks/index.ts +1 -1
  204. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  205. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  206. package/src/hooks/useEventTheme.test.ts +119 -43
  207. package/src/hooks/useEventTheme.ts +84 -55
  208. package/src/index.ts +3 -1
  209. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  210. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  211. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  213. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  214. package/src/rbac/secureClient.ts +4 -2
  215. package/src/services/EventService.ts +0 -66
  216. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  217. package/src/styles/index.ts +1 -1
  218. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  219. package/src/theming/parseEventColours.ts +123 -0
  220. package/src/theming/runtime.ts +3 -0
  221. package/src/types/__tests__/file-reference.test.ts +447 -0
  222. package/src/utils/formatDate.test.ts +11 -11
  223. package/src/utils/formatting.ts +3 -2
  224. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  225. package/dist/chunk-BHWIUEYH.js.map +0 -1
  226. package/dist/chunk-CGURJ27Z.js.map +0 -1
  227. package/dist/chunk-FKFHZUGF.js.map +0 -1
  228. package/dist/chunk-GKHF54DI 2.js +0 -619
  229. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  230. package/dist/chunk-GZRXOUBE.js.map +0 -1
  231. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  232. package/dist/chunk-NZ32EONV.js.map +0 -1
  233. package/dist/chunk-O3NWNXDY 2.js +0 -76
  234. package/dist/chunk-QPI2CCBA.js.map +0 -1
  235. package/dist/chunk-SMJZMKYN.js.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  237. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  238. package/dist/chunk-VKOCWWVY.js.map +0 -1
  239. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  240. package/dist/index 3.js +0 -856
  241. package/dist/providers 3.js +0 -38
  242. package/dist/providers.js 3.map +0 -1
  243. package/dist/types 3.js +0 -128
  244. package/dist/types.js 3.map +0 -1
  245. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  246. package/dist/utils.js 3.map +0 -1
  247. package/dist/validation 3.js +0 -479
  248. package/src/styles/semantic.css +0 -24
  249. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-OKDYRW2S.js.map} +0 -0
  250. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  251. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  252. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  253. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  254. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  255. /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -1,1564 +0,0 @@
1
- import {
2
- createAuditManager,
3
- emitAuditEvent,
4
- setGlobalAuditManager
5
- } from "./chunk-3DBFLLLU.js";
6
-
7
- // src/rbac/types.ts
8
- var RBACError = class extends Error {
9
- constructor(message, code, context) {
10
- super(message);
11
- this.code = code;
12
- this.context = context;
13
- this.name = "RBACError";
14
- }
15
- };
16
- var PermissionDeniedError = class extends RBACError {
17
- constructor(permission, context) {
18
- super(
19
- `Permission denied: ${permission}`,
20
- "PERMISSION_DENIED",
21
- { permission, ...context }
22
- );
23
- this.name = "PermissionDeniedError";
24
- }
25
- };
26
- var OrganisationContextRequiredError = class extends RBACError {
27
- constructor() {
28
- super(
29
- "Organisation context is required for this operation",
30
- "ORGANISATION_CONTEXT_REQUIRED"
31
- );
32
- this.name = "OrganisationContextRequiredError";
33
- }
34
- };
35
- var RBACNotInitializedError = class extends RBACError {
36
- constructor() {
37
- super(
38
- "RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup",
39
- "RBAC_NOT_INITIALIZED"
40
- );
41
- this.name = "RBACNotInitializedError";
42
- }
43
- };
44
- var InvalidScopeError = class extends RBACError {
45
- constructor(scope, reason) {
46
- super(
47
- `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,
48
- "INVALID_SCOPE",
49
- { scope, reason }
50
- );
51
- this.name = "InvalidScopeError";
52
- }
53
- };
54
- var MissingUserContextError = class extends RBACError {
55
- constructor() {
56
- super(
57
- "User context is required but not available. Make sure to wrap your app with an auth provider.",
58
- "MISSING_USER_CONTEXT"
59
- );
60
- this.name = "MissingUserContextError";
61
- }
62
- };
63
-
64
- // src/rbac/cache.ts
65
- var RBACCache = class {
66
- constructor() {
67
- this.cache = /* @__PURE__ */ new Map();
68
- this.TTL = 60 * 1e3;
69
- // 60 seconds
70
- this.invalidationCallbacks = /* @__PURE__ */ new Set();
71
- }
72
- /**
73
- * Get a value from the cache
74
- *
75
- * @param key - Cache key
76
- * @returns Cached value or null if not found/expired
77
- */
78
- get(key) {
79
- const entry = this.cache.get(key);
80
- if (!entry) {
81
- return null;
82
- }
83
- if (Date.now() > entry.expires) {
84
- this.cache.delete(key);
85
- return null;
86
- }
87
- return entry.data;
88
- }
89
- /**
90
- * Set a value in the cache
91
- *
92
- * @param key - Cache key
93
- * @param data - Data to cache
94
- * @param ttl - Time to live in milliseconds (defaults to 60s)
95
- */
96
- set(key, data, ttl = this.TTL) {
97
- const expires = ttl <= 0 ? Date.now() - 1 : Date.now() + ttl;
98
- this.cache.set(key, {
99
- data,
100
- expires
101
- });
102
- }
103
- /**
104
- * Delete a specific key from the cache
105
- *
106
- * @param key - Cache key to delete
107
- */
108
- delete(key) {
109
- this.cache.delete(key);
110
- }
111
- /**
112
- * Invalidate cache entries matching a pattern
113
- *
114
- * @param pattern - Pattern to match against cache keys
115
- */
116
- invalidate(pattern) {
117
- const trimmedPattern = pattern?.trim();
118
- if (!trimmedPattern) {
119
- return;
120
- }
121
- const matcher = this.createMatcher(trimmedPattern);
122
- const keysToDelete = [];
123
- for (const key of this.cache.keys()) {
124
- if (matcher(key)) {
125
- keysToDelete.push(key);
126
- }
127
- }
128
- keysToDelete.forEach((key) => this.cache.delete(key));
129
- this.invalidationCallbacks.forEach((callback) => callback(trimmedPattern));
130
- }
131
- createMatcher(pattern) {
132
- if (pattern.includes("*")) {
133
- const escapedSegments = pattern.split("*").map((segment) => segment.replace(/[|\\{}()[\]^$+?.-]/g, "\\$&"));
134
- const regexPattern = escapedSegments.join(".*");
135
- const regex = new RegExp(regexPattern);
136
- return (key) => regex.test(key);
137
- }
138
- return (key) => key.includes(pattern);
139
- }
140
- /**
141
- * Clear all cache entries
142
- */
143
- clear() {
144
- this.cache.clear();
145
- }
146
- /**
147
- * Get cache statistics
148
- */
149
- getStats() {
150
- return {
151
- size: this.cache.size,
152
- ttl: this.TTL,
153
- keys: Array.from(this.cache.keys())
154
- };
155
- }
156
- /**
157
- * Add an invalidation callback
158
- *
159
- * @param callback - Function to call when cache is invalidated
160
- */
161
- onInvalidate(callback) {
162
- this.invalidationCallbacks.add(callback);
163
- return () => {
164
- this.invalidationCallbacks.delete(callback);
165
- };
166
- }
167
- /**
168
- * Generate cache key for permission check (simplified signature)
169
- *
170
- * @param userId - User ID
171
- * @param permission - Permission string
172
- * @param organisationId - Organisation ID (optional)
173
- * @param eventId - Event ID (optional)
174
- * @param appId - App ID (optional)
175
- * @param pageId - Page ID (optional)
176
- * @returns String cache key
177
- */
178
- static generateKey(userId, permission, organisationId, eventId, appId, pageId) {
179
- const parts = [
180
- "perm",
181
- userId,
182
- organisationId || "null",
183
- eventId || "null",
184
- appId || "null",
185
- permission || "null",
186
- pageId || "null"
187
- ];
188
- return parts.join(":");
189
- }
190
- /**
191
- * Generate cache key for permission check (object signature)
192
- *
193
- * @param key - Permission cache key object
194
- * @returns String cache key
195
- */
196
- static generatePermissionKey(key) {
197
- const parts = [
198
- "perm",
199
- key.userId,
200
- key.organisationId || "null",
201
- key.eventId || "null",
202
- key.appId || "null",
203
- key.permission || "null",
204
- key.pageId || "null"
205
- ];
206
- return parts.join(":");
207
- }
208
- /**
209
- * Generate cache key for access level
210
- *
211
- * @param userId - User ID
212
- * @param organisationId - Organisation ID
213
- * @param eventId - Event ID (optional)
214
- * @param appId - App ID (optional)
215
- * @returns String cache key
216
- */
217
- static generateAccessLevelKey(userId, organisationId, eventId, appId) {
218
- const parts = [
219
- "access",
220
- userId,
221
- organisationId,
222
- eventId || "null",
223
- appId || "null"
224
- ];
225
- return parts.join(":");
226
- }
227
- /**
228
- * Generate cache key for permission map
229
- *
230
- * @param userId - User ID
231
- * @param organisationId - Organisation ID
232
- * @param eventId - Event ID (optional)
233
- * @param appId - App ID (optional)
234
- * @returns String cache key
235
- */
236
- static generatePermissionMapKey(userId, organisationId, eventId, appId) {
237
- const parts = [
238
- "map",
239
- userId,
240
- organisationId,
241
- eventId || "null",
242
- appId || "null"
243
- ];
244
- return parts.join(":");
245
- }
246
- };
247
- var rbacCache = new RBACCache();
248
- var CACHE_PATTERNS = {
249
- USER: (userId) => `:${userId}:`,
250
- ORGANISATION: (organisationId) => `:${organisationId}:`,
251
- EVENT: (eventId) => `:${eventId}:`,
252
- APP: (appId) => `:${appId}`,
253
- PERMISSION: (userId, organisationId) => `perm:${userId}:${organisationId}:`
254
- };
255
-
256
- // src/rbac/cache-invalidation.ts
257
- var INVALIDATION_PATTERNS = {
258
- // User-level invalidation
259
- USER_ROLES_CHANGED: (userId) => [
260
- CACHE_PATTERNS.USER(userId),
261
- `perm:${userId}:*`,
262
- `access:${userId}:*`,
263
- `map:${userId}:*`
264
- ],
265
- // Organisation-level invalidation
266
- ORGANISATION_PERMISSIONS_CHANGED: (organisationId) => [
267
- CACHE_PATTERNS.ORGANISATION(organisationId),
268
- `perm:*:${organisationId}:*`,
269
- `access:*:${organisationId}:*`,
270
- `map:*:${organisationId}:*`
271
- ],
272
- // Event-level invalidation
273
- EVENT_PERMISSIONS_CHANGED: (eventId) => [
274
- CACHE_PATTERNS.EVENT(eventId),
275
- `perm:*:*:${eventId}:*`,
276
- `access:*:*:${eventId}:*`,
277
- `map:*:*:${eventId}:*`
278
- ],
279
- // App-level invalidation
280
- APP_PERMISSIONS_CHANGED: (appId) => [
281
- CACHE_PATTERNS.APP(appId),
282
- `perm:*:*:*:${appId}:*`,
283
- `access:*:*:*:${appId}`,
284
- `map:*:*:*:${appId}`
285
- ],
286
- // Page-level invalidation
287
- PAGE_PERMISSIONS_CHANGED: (pageId) => [
288
- `perm:*:*:*:*:${pageId}`,
289
- `map:*:*:*:*`
290
- ]
291
- };
292
- var RBACCacheInvalidationManager = class {
293
- constructor(supabase) {
294
- this.invalidationCallbacks = /* @__PURE__ */ new Set();
295
- this.supabase = supabase;
296
- this.setupRealtimeSubscriptions();
297
- }
298
- /**
299
- * Add a callback for cache invalidation events
300
- *
301
- * @param callback - Function to call when cache is invalidated
302
- * @returns Unsubscribe function
303
- */
304
- onInvalidation(callback) {
305
- this.invalidationCallbacks.add(callback);
306
- return () => this.invalidationCallbacks.delete(callback);
307
- }
308
- /**
309
- * Invalidate cache for a specific user
310
- *
311
- * @param userId - User ID
312
- * @param reason - Reason for invalidation
313
- */
314
- invalidateUser(userId, reason) {
315
- const patterns = INVALIDATION_PATTERNS.USER_ROLES_CHANGED(userId);
316
- this.invalidatePatterns(patterns, reason);
317
- }
318
- /**
319
- * Invalidate cache for a specific organisation
320
- *
321
- * @param organisationId - Organisation ID
322
- * @param reason - Reason for invalidation
323
- */
324
- invalidateOrganisation(organisationId, reason) {
325
- const patterns = INVALIDATION_PATTERNS.ORGANISATION_PERMISSIONS_CHANGED(organisationId);
326
- this.invalidatePatterns(patterns, reason);
327
- }
328
- /**
329
- * Invalidate cache for a specific event
330
- *
331
- * @param eventId - Event ID
332
- * @param reason - Reason for invalidation
333
- */
334
- invalidateEvent(eventId, reason) {
335
- const patterns = INVALIDATION_PATTERNS.EVENT_PERMISSIONS_CHANGED(eventId);
336
- this.invalidatePatterns(patterns, reason);
337
- }
338
- /**
339
- * Invalidate cache for a specific app
340
- *
341
- * @param appId - App ID
342
- * @param reason - Reason for invalidation
343
- */
344
- invalidateApp(appId, reason) {
345
- const patterns = INVALIDATION_PATTERNS.APP_PERMISSIONS_CHANGED(appId);
346
- this.invalidatePatterns(patterns, reason);
347
- }
348
- /**
349
- * Invalidate cache for a specific page
350
- *
351
- * @param pageId - Page ID
352
- * @param reason - Reason for invalidation
353
- */
354
- invalidatePage(pageId, reason) {
355
- const patterns = INVALIDATION_PATTERNS.PAGE_PERMISSIONS_CHANGED(pageId);
356
- this.invalidatePatterns(patterns, reason);
357
- }
358
- /**
359
- * Invalidate cache patterns and notify callbacks
360
- *
361
- * @param patterns - Array of cache patterns to invalidate
362
- * @param reason - Reason for invalidation
363
- */
364
- invalidatePatterns(patterns, reason) {
365
- console.log(`[RBAC Cache] Invalidating patterns: ${patterns.join(", ")} (${reason})`);
366
- patterns.forEach((pattern) => {
367
- rbacCache.invalidate(pattern);
368
- });
369
- this.invalidationCallbacks.forEach((callback) => {
370
- patterns.forEach((pattern) => callback(pattern));
371
- });
372
- emitAuditEvent({
373
- type: "permission_check",
374
- userId: "system",
375
- organisationId: "00000000-0000-0000-0000-000000000000",
376
- permission: "cache:invalidate",
377
- decision: true,
378
- source: "api",
379
- duration_ms: 0,
380
- metadata: {
381
- reason,
382
- patterns,
383
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
384
- cache_invalidation: true
385
- }
386
- }).catch((error) => {
387
- console.warn("[RBAC Cache] Failed to log cache invalidation audit event:", error);
388
- });
389
- }
390
- /**
391
- * Setup realtime subscriptions for automatic cache invalidation
392
- */
393
- setupRealtimeSubscriptions() {
394
- if (!this.supabase.channel || typeof this.supabase.channel !== "function") {
395
- console.log("[RBAC Cache] Realtime not available, skipping subscriptions");
396
- return;
397
- }
398
- this.supabase.channel("rbac_organisation_roles_changes").on("postgres_changes", {
399
- event: "*",
400
- schema: "public",
401
- table: "rbac_organisation_roles"
402
- }, (payload) => {
403
- const { organisation_id, user_id } = payload.new || payload.old || {};
404
- if (organisation_id) {
405
- this.invalidateOrganisation(organisation_id, `organisation_role_${payload.eventType}`);
406
- }
407
- if (user_id) {
408
- this.invalidateUser(user_id, `organisation_role_${payload.eventType}`);
409
- }
410
- }).subscribe();
411
- this.supabase.channel("rbac_event_app_roles_changes").on("postgres_changes", {
412
- event: "*",
413
- schema: "public",
414
- table: "rbac_event_app_roles"
415
- }, (payload) => {
416
- const { organisation_id, user_id, event_id, app_id } = payload.new || payload.old || {};
417
- if (organisation_id) {
418
- this.invalidateOrganisation(organisation_id, `event_app_role_${payload.eventType}`);
419
- }
420
- if (user_id) {
421
- this.invalidateUser(user_id, `event_app_role_${payload.eventType}`);
422
- }
423
- if (event_id) {
424
- this.invalidateEvent(event_id, `event_app_role_${payload.eventType}`);
425
- }
426
- if (app_id) {
427
- this.invalidateApp(app_id, `event_app_role_${payload.eventType}`);
428
- }
429
- }).subscribe();
430
- this.supabase.channel("rbac_global_roles_changes").on("postgres_changes", {
431
- event: "*",
432
- schema: "public",
433
- table: "rbac_global_roles"
434
- }, (payload) => {
435
- const { user_id } = payload.new || payload.old || {};
436
- if (user_id) {
437
- this.invalidateUser(user_id, `global_role_${payload.eventType}`);
438
- }
439
- }).subscribe();
440
- this.supabase.channel("rbac_page_permissions_changes").on("postgres_changes", {
441
- event: "*",
442
- schema: "public",
443
- table: "rbac_page_permissions"
444
- }, (payload) => {
445
- const { organisation_id, app_page_id, role_id } = payload.new || payload.old || {};
446
- if (organisation_id) {
447
- this.invalidateOrganisation(organisation_id, `page_permission_${payload.eventType}`);
448
- }
449
- if (app_page_id) {
450
- this.invalidatePage(app_page_id, `page_permission_${payload.eventType}`);
451
- }
452
- }).subscribe();
453
- }
454
- /**
455
- * Manually trigger cache invalidation for all users in an organisation
456
- *
457
- * @param organisationId - Organisation ID
458
- * @param reason - Reason for invalidation
459
- */
460
- async invalidateAllUsersInOrganisation(organisationId, reason) {
461
- const { data: users } = await this.supabase.from("rbac_organisation_roles").select("user_id").eq("organisation_id", organisationId).eq("is_active", true);
462
- if (users) {
463
- users.forEach(({ user_id }) => {
464
- this.invalidateUser(user_id, reason);
465
- });
466
- }
467
- }
468
- /**
469
- * Clear all cache entries
470
- */
471
- clearAllCache() {
472
- console.log("[RBAC Cache] Clearing all cache entries");
473
- rbacCache.clear();
474
- }
475
- };
476
- var globalCacheInvalidationManager = null;
477
- function initializeCacheInvalidation(supabase) {
478
- globalCacheInvalidationManager = new RBACCacheInvalidationManager(supabase);
479
- return globalCacheInvalidationManager;
480
- }
481
-
482
- // src/rbac/errors.ts
483
- var RATE_LIMIT_STATUS_CODES = /* @__PURE__ */ new Set([429]);
484
- var AUTH_STATUS_CODES = /* @__PURE__ */ new Set([401]);
485
- var AUTHZ_STATUS_CODES = /* @__PURE__ */ new Set([403]);
486
- function normalize(value) {
487
- if (!value) {
488
- return "";
489
- }
490
- if (typeof value === "string") {
491
- return value.toLowerCase();
492
- }
493
- if (value instanceof Error && typeof value.message === "string") {
494
- return value.message.toLowerCase();
495
- }
496
- return String(value).toLowerCase();
497
- }
498
- function categorizeError(error) {
499
- if (error instanceof PermissionDeniedError) {
500
- return "authorization_error" /* AUTHORIZATION */;
501
- }
502
- if (error instanceof OrganisationContextRequiredError || error instanceof InvalidScopeError) {
503
- return "validation_error" /* VALIDATION */;
504
- }
505
- if (error instanceof MissingUserContextError) {
506
- return "authentication_error" /* AUTHENTICATION */;
507
- }
508
- if (error instanceof RBACError) {
509
- switch (error.code) {
510
- case "PERMISSION_DENIED":
511
- return "authorization_error" /* AUTHORIZATION */;
512
- case "ORGANISATION_CONTEXT_REQUIRED":
513
- case "INVALID_SCOPE":
514
- return "validation_error" /* VALIDATION */;
515
- case "MISSING_USER_CONTEXT":
516
- return "authentication_error" /* AUTHENTICATION */;
517
- default:
518
- break;
519
- }
520
- }
521
- if (error && typeof error === "object") {
522
- const status = error.status;
523
- if (typeof status === "number") {
524
- if (RATE_LIMIT_STATUS_CODES.has(status)) {
525
- return "rate_limit_error" /* RATE_LIMIT */;
526
- }
527
- if (AUTH_STATUS_CODES.has(status)) {
528
- return "authentication_error" /* AUTHENTICATION */;
529
- }
530
- if (AUTHZ_STATUS_CODES.has(status)) {
531
- return "authorization_error" /* AUTHORIZATION */;
532
- }
533
- if (status >= 500) {
534
- return "database_error" /* DATABASE */;
535
- }
536
- }
537
- const codeValue = normalize(error.code);
538
- if (codeValue) {
539
- if (codeValue.includes("network")) {
540
- return "network_error" /* NETWORK */;
541
- }
542
- if (codeValue.includes("postgres") || codeValue.includes("database") || codeValue.includes("db")) {
543
- return "database_error" /* DATABASE */;
544
- }
545
- if (codeValue.includes("rate")) {
546
- return "rate_limit_error" /* RATE_LIMIT */;
547
- }
548
- if (codeValue.includes("auth")) {
549
- return "authentication_error" /* AUTHENTICATION */;
550
- }
551
- if (codeValue.includes("permission")) {
552
- return "authorization_error" /* AUTHORIZATION */;
553
- }
554
- if (codeValue.includes("scope") || codeValue.includes("invalid")) {
555
- return "validation_error" /* VALIDATION */;
556
- }
557
- }
558
- }
559
- const message = normalize(error);
560
- if (message.includes("timeout") || message.includes("network") || message.includes("fetch")) {
561
- return "network_error" /* NETWORK */;
562
- }
563
- if (message.includes("postgres") || message.includes("database") || message.includes("connection")) {
564
- return "database_error" /* DATABASE */;
565
- }
566
- if (message.includes("rate limit") || message.includes("too many requests")) {
567
- return "rate_limit_error" /* RATE_LIMIT */;
568
- }
569
- if (message.includes("permission") || message.includes("forbidden")) {
570
- return "authorization_error" /* AUTHORIZATION */;
571
- }
572
- if (message.includes("auth") || message.includes("token") || message.includes("session")) {
573
- return "authentication_error" /* AUTHENTICATION */;
574
- }
575
- if (message.includes("invalid") || message.includes("scope") || message.includes("validation")) {
576
- return "validation_error" /* VALIDATION */;
577
- }
578
- return "unknown_error" /* UNKNOWN */;
579
- }
580
- function mapErrorCategoryToSecurityEventType(category) {
581
- switch (category) {
582
- case "authorization_error" /* AUTHORIZATION */:
583
- return "permission_denied";
584
- case "network_error" /* NETWORK */:
585
- return "network_error";
586
- case "database_error" /* DATABASE */:
587
- return "database_error";
588
- case "validation_error" /* VALIDATION */:
589
- return "validation_error";
590
- case "rate_limit_error" /* RATE_LIMIT */:
591
- return "rate_limit_error";
592
- case "authentication_error" /* AUTHENTICATION */:
593
- return "authentication_error";
594
- case "unknown_error" /* UNKNOWN */:
595
- default:
596
- return "unknown_error";
597
- }
598
- }
599
-
600
- // src/rbac/security.ts
601
- var RBACSecurityValidator = class {
602
- /**
603
- * Validate permission string format
604
- * @param permission - Permission string to validate
605
- * @returns True if valid, false otherwise
606
- */
607
- static validatePermission(permission) {
608
- if (typeof permission !== "string" || permission.length === 0) {
609
- return false;
610
- }
611
- const permissionRegex = /^(read|create|update|delete):[a-z0-9._-]+$/;
612
- return permissionRegex.test(permission);
613
- }
614
- /**
615
- * Validate UUID format
616
- * @param uuid - UUID string to validate
617
- * @returns True if valid, false otherwise
618
- */
619
- static validateUUID(uuid) {
620
- if (typeof uuid !== "string" || uuid.length === 0) {
621
- return false;
622
- }
623
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
624
- return uuidRegex.test(uuid);
625
- }
626
- /**
627
- * Validate scope object
628
- * @param scope - Scope object to validate
629
- * @returns True if valid, false otherwise
630
- */
631
- static validateScope(scope) {
632
- if (!scope || typeof scope !== "object") {
633
- return false;
634
- }
635
- if (scope.organisationId !== void 0) {
636
- if (typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
637
- return false;
638
- }
639
- if (scope.organisationId && !this.validateUUID(scope.organisationId)) {
640
- return false;
641
- }
642
- }
643
- if (scope.eventId && typeof scope.eventId !== "string") {
644
- return false;
645
- }
646
- if (scope.appId && !this.validateUUID(scope.appId)) {
647
- return false;
648
- }
649
- return !!(scope.organisationId || scope.eventId || scope.appId);
650
- }
651
- /**
652
- * Sanitize input string to prevent injection attacks
653
- * @param input - Input string to sanitize
654
- * @returns Sanitized string
655
- */
656
- static sanitizeInput(input) {
657
- if (typeof input !== "string") {
658
- return "";
659
- }
660
- return input.replace(/<[^>]*>/g, "").replace(/[<>\"'&]/g, "").replace(/[;()]/g, "").replace(/javascript:/gi, "").replace(/data:/gi, "").trim();
661
- }
662
- /**
663
- * Validate user ID format
664
- * @param userId - User ID to validate
665
- * @returns True if valid, false otherwise
666
- */
667
- static validateUserId(userId) {
668
- return this.validateUUID(userId);
669
- }
670
- /**
671
- * Check if permission is a wildcard permission
672
- * @param permission - Permission string to check
673
- * @returns True if wildcard, false otherwise
674
- */
675
- static isWildcardPermission(permission) {
676
- return permission.includes("*") || permission.endsWith(":*");
677
- }
678
- /**
679
- * Validate permission hierarchy
680
- * @param permission - Permission to validate
681
- * @param requiredOperation - Required operation
682
- * @returns True if permission matches or is higher in hierarchy
683
- */
684
- static validatePermissionHierarchy(permission, requiredOperation) {
685
- if (!this.validatePermission(permission)) {
686
- return false;
687
- }
688
- const [operation] = permission.split(":");
689
- const hierarchy = ["read", "create", "update", "delete"];
690
- const permissionLevel = hierarchy.indexOf(operation);
691
- const requiredLevel = hierarchy.indexOf(requiredOperation);
692
- if (permissionLevel === -1 || requiredLevel === -1) {
693
- return false;
694
- }
695
- return permissionLevel >= requiredLevel;
696
- }
697
- /**
698
- * Rate limiting check (placeholder for future implementation)
699
- * @param userId - User ID
700
- * @param operation - Operation being performed
701
- * @returns True if within rate limit, false otherwise
702
- */
703
- static async checkRateLimit(userId, operation) {
704
- return true;
705
- }
706
- /**
707
- * Validate context requirements for security
708
- * @param scope - Scope object
709
- * @param appId - Application ID
710
- * @returns True if context is valid, false otherwise
711
- */
712
- static validateContextRequirements(scope, appId) {
713
- if (!scope.organisationId) {
714
- return false;
715
- }
716
- if (appId && scope.appId === appId) {
717
- if (!scope.eventId) {
718
- return false;
719
- }
720
- }
721
- return true;
722
- }
723
- /**
724
- * Log security event for monitoring
725
- * @param event - Security event details
726
- */
727
- static logSecurityEvent(event) {
728
- const securityEvent = {
729
- ...event,
730
- timestamp: event.timestamp || /* @__PURE__ */ new Date(),
731
- severity: this.getEventSeverity(event.type)
732
- };
733
- if (import.meta.env.MODE === "development") {
734
- console.warn("[RBAC Security]", securityEvent);
735
- }
736
- }
737
- /**
738
- * Get severity level for security event
739
- * @param eventType - Type of security event
740
- * @returns Severity level
741
- */
742
- static getEventSeverity(eventType) {
743
- switch (eventType) {
744
- case "permission_denied":
745
- return "low";
746
- case "invalid_input":
747
- case "rate_limit_exceeded":
748
- case "rate_limit_error":
749
- case "network_error":
750
- return "medium";
751
- case "validation_error":
752
- return "high";
753
- case "authentication_error":
754
- case "database_error":
755
- return "critical";
756
- case "suspicious_activity":
757
- case "unknown_error":
758
- return "high";
759
- default:
760
- return "low";
761
- }
762
- }
763
- };
764
- var DEFAULT_SECURITY_CONFIG = {
765
- enableInputValidation: true,
766
- enableRateLimiting: true,
767
- enableAuditLogging: true,
768
- maxPermissionChecksPerMinute: 1e3,
769
- // Increased from 100 to 1000 for normal app usage
770
- suspiciousActivityThreshold: 10
771
- };
772
- var RBACSecurityMiddleware = class {
773
- constructor(config = DEFAULT_SECURITY_CONFIG) {
774
- /**
775
- * In-memory rate limiting cache (sliding window)
776
- * Note: For production, this should use Redis or Supabase Edge Functions
777
- */
778
- this.rateLimitCache = /* @__PURE__ */ new Map();
779
- this.config = config;
780
- this._startCleanupInterval();
781
- }
782
- /**
783
- * Start periodic cleanup of expired entries
784
- */
785
- _startCleanupInterval() {
786
- setInterval(() => {
787
- this.clearExpiredEntries();
788
- }, 5 * 60 * 1e3);
789
- }
790
- /**
791
- * Validate input before processing
792
- * @param input - Input to validate
793
- * @param context - Security context
794
- * @returns Validation result
795
- */
796
- async validateInput(input, context) {
797
- const errors = [];
798
- if (!RBACSecurityValidator.validateUserId(context.userId)) {
799
- errors.push("Invalid user ID format");
800
- }
801
- if (!context.organisationId) {
802
- errors.push("Organisation ID is required");
803
- } else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {
804
- errors.push("Invalid organisation ID format");
805
- }
806
- if (input.permission && !RBACSecurityValidator.validatePermission(input.permission)) {
807
- errors.push("Invalid permission format");
808
- }
809
- if (input.scope && !RBACSecurityValidator.validateScope(input.scope)) {
810
- errors.push("Invalid scope format");
811
- }
812
- if (this.config.enableInputValidation) {
813
- if (context.ipAddress && typeof context.ipAddress !== "string") {
814
- errors.push("Invalid IP address format");
815
- }
816
- if (context.userAgent && typeof context.userAgent !== "string") {
817
- errors.push("Invalid user agent format");
818
- }
819
- }
820
- if (errors.length > 0) {
821
- RBACSecurityValidator.logSecurityEvent({
822
- type: "invalid_input",
823
- userId: context.userId,
824
- details: { errors, input: this.sanitizeInput(JSON.stringify(input)) }
825
- });
826
- }
827
- return {
828
- isValid: errors.length === 0,
829
- errors
830
- };
831
- }
832
- /**
833
- * Check rate limiting
834
- * @param context - Security context
835
- * @returns Rate limit check result
836
- */
837
- async checkRateLimit(context) {
838
- if (!this.config.enableRateLimiting) {
839
- return { isAllowed: true, remaining: this.config.maxPermissionChecksPerMinute };
840
- }
841
- const isAllowed = await this._checkRateLimitInternal(context.userId);
842
- const remaining = isAllowed ? this.config.maxPermissionChecksPerMinute - this._getRequestCount(context.userId) : 0;
843
- return {
844
- isAllowed,
845
- remaining: Math.max(0, remaining)
846
- };
847
- }
848
- async _checkRateLimitInternal(userId) {
849
- const now = Date.now();
850
- const windowMs = 60 * 1e3;
851
- const entries = this.rateLimitCache.get(userId) || [];
852
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
853
- const requestCount = validEntries.length;
854
- const isAllowed = requestCount < this.config.maxPermissionChecksPerMinute;
855
- if (isAllowed) {
856
- validEntries.push({ timestamp: now });
857
- }
858
- this.rateLimitCache.set(userId, validEntries);
859
- return isAllowed;
860
- }
861
- _getRequestCount(userId) {
862
- const now = Date.now();
863
- const windowMs = 60 * 1e3;
864
- const entries = this.rateLimitCache.get(userId) || [];
865
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
866
- return validEntries.length;
867
- }
868
- /**
869
- * Clear old rate limit entries to prevent memory leaks
870
- * Should be called periodically (e.g., every 5 minutes)
871
- */
872
- clearExpiredEntries() {
873
- const now = Date.now();
874
- const windowMs = 60 * 1e3;
875
- for (const [userId, entries] of this.rateLimitCache.entries()) {
876
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
877
- if (validEntries.length === 0) {
878
- this.rateLimitCache.delete(userId);
879
- } else {
880
- this.rateLimitCache.set(userId, validEntries);
881
- }
882
- }
883
- }
884
- /**
885
- * Sanitize input data
886
- * @param input - Input to sanitize
887
- * @returns Sanitized input
888
- */
889
- sanitizeInput(input) {
890
- return RBACSecurityValidator.sanitizeInput(input);
891
- }
892
- };
893
-
894
- // src/rbac/engine.ts
895
- var RBACEngine = class {
896
- constructor(supabase, securityConfig) {
897
- this.supabase = supabase;
898
- const mergedSecurityConfig = {
899
- ...DEFAULT_SECURITY_CONFIG,
900
- ...securityConfig
901
- };
902
- this.securityMiddleware = new RBACSecurityMiddleware(mergedSecurityConfig);
903
- initializeCacheInvalidation(supabase);
904
- }
905
- /**
906
- * Check if a user has a specific permission
907
- *
908
- * This method now delegates to the database RPC function for all the heavy lifting.
909
- *
910
- * @param input - Permission check input
911
- * @param securityContext - Security context for validation (required)
912
- * @returns Promise resolving to permission result
913
- */
914
- async isPermitted(input, securityContext) {
915
- const startTime = Date.now();
916
- const { userId, permission, scope, pageId } = input;
917
- let cacheHit = false;
918
- let cacheSource = "rpc";
919
- try {
920
- const validation = await this.securityMiddleware.validateInput(input, securityContext);
921
- if (!validation.isValid) {
922
- RBACSecurityValidator.logSecurityEvent({
923
- type: "invalid_input",
924
- userId,
925
- details: { errors: validation.errors, input: JSON.stringify(input) }
926
- });
927
- return false;
928
- }
929
- const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);
930
- if (!rateLimit.isAllowed) {
931
- RBACSecurityValidator.logSecurityEvent({
932
- type: "rate_limit_exceeded",
933
- userId,
934
- details: { remaining: rateLimit.remaining }
935
- });
936
- return false;
937
- }
938
- if (!RBACSecurityValidator.validateUserId(userId)) {
939
- RBACSecurityValidator.logSecurityEvent({
940
- type: "invalid_input",
941
- userId,
942
- details: { error: "Invalid user ID format" }
943
- });
944
- return false;
945
- }
946
- if (!RBACSecurityValidator.validatePermission(permission)) {
947
- RBACSecurityValidator.logSecurityEvent({
948
- type: "invalid_input",
949
- userId,
950
- details: { error: "Invalid permission format", permission }
951
- });
952
- return false;
953
- }
954
- if (!RBACSecurityValidator.validateScope(scope)) {
955
- RBACSecurityValidator.logSecurityEvent({
956
- type: "invalid_input",
957
- userId,
958
- details: { error: "Invalid scope format", scope }
959
- });
960
- return false;
961
- }
962
- const cacheKey = RBACCache.generateKey(
963
- userId,
964
- permission,
965
- scope.organisationId,
966
- scope.eventId,
967
- scope.appId,
968
- pageId
969
- );
970
- const cached = rbacCache.get(cacheKey);
971
- if (cached !== null) {
972
- cacheHit = true;
973
- cacheSource = "memory";
974
- const duration2 = Date.now() - startTime;
975
- if (scope.organisationId) {
976
- const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
977
- await emitAuditEvent({
978
- type: "permission_check",
979
- userId,
980
- organisationId: scope.organisationId,
981
- eventId: scope.eventId,
982
- appId: scope.appId,
983
- pageId: resolvedPageId,
984
- permission,
985
- decision: cached,
986
- source: "api",
987
- duration_ms: duration2,
988
- cache_hit: true,
989
- cache_source: "memory"
990
- });
991
- }
992
- return cached;
993
- }
994
- const { data, error } = await this.supabase.rpc("rbac_check_permission_simplified", {
995
- p_user_id: userId,
996
- p_permission: permission,
997
- p_organisation_id: scope.organisationId || void 0,
998
- p_event_id: scope.eventId || void 0,
999
- p_app_id: scope.appId || void 0,
1000
- p_page_id: pageId || void 0
1001
- });
1002
- if (error) {
1003
- console.error("[RBACEngine] RPC error:", error);
1004
- const category = categorizeError(error);
1005
- const eventType = mapErrorCategoryToSecurityEventType(category);
1006
- const errorDetails = error;
1007
- RBACSecurityValidator.logSecurityEvent({
1008
- type: eventType,
1009
- userId,
1010
- details: {
1011
- error: errorDetails?.message || "RPC call failed",
1012
- code: errorDetails?.code,
1013
- hint: errorDetails?.hint,
1014
- details: errorDetails?.details,
1015
- permission,
1016
- scope: JSON.stringify(scope),
1017
- category
1018
- }
1019
- });
1020
- return false;
1021
- }
1022
- const hasPermission2 = data === true;
1023
- rbacCache.set(cacheKey, hasPermission2, 6e4);
1024
- const duration = Date.now() - startTime;
1025
- if (scope.organisationId) {
1026
- const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
1027
- await emitAuditEvent({
1028
- type: hasPermission2 ? "permission_check" : "permission_denied",
1029
- userId,
1030
- organisationId: scope.organisationId,
1031
- eventId: scope.eventId,
1032
- appId: scope.appId,
1033
- pageId: resolvedPageId,
1034
- permission,
1035
- decision: hasPermission2,
1036
- source: "api",
1037
- duration_ms: duration,
1038
- cache_hit: cacheHit,
1039
- cache_source: cacheSource
1040
- });
1041
- }
1042
- return hasPermission2;
1043
- } catch (error) {
1044
- const category = categorizeError(error);
1045
- const eventType = mapErrorCategoryToSecurityEventType(category);
1046
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1047
- RBACSecurityValidator.logSecurityEvent({
1048
- type: eventType,
1049
- userId,
1050
- details: {
1051
- error: errorMessage,
1052
- permission,
1053
- scope: JSON.stringify(scope),
1054
- category
1055
- }
1056
- });
1057
- console.error("[RBACEngine] Permission check failed:", error);
1058
- return false;
1059
- }
1060
- }
1061
- /**
1062
- * Get user's access level in a scope
1063
- *
1064
- * This is derived from roles, not permissions.
1065
- *
1066
- * @param input - Access level input
1067
- * @returns Promise resolving to access level
1068
- */
1069
- async getAccessLevel(input) {
1070
- const { userId, scope } = input;
1071
- const cacheKey = RBACCache.generateAccessLevelKey(
1072
- userId,
1073
- scope.organisationId || "",
1074
- scope.eventId,
1075
- scope.appId
1076
- );
1077
- const cached = rbacCache.get(cacheKey);
1078
- if (cached) {
1079
- return cached;
1080
- }
1081
- const now = (/* @__PURE__ */ new Date()).toISOString();
1082
- const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1083
- if (isSuperAdmin2) {
1084
- rbacCache.set(cacheKey, "super", 6e4);
1085
- return "super";
1086
- }
1087
- if (scope.organisationId) {
1088
- const { data: orgRole } = await this.supabase.from("rbac_organisation_roles").select("role").eq("user_id", userId).eq("organisation_id", scope.organisationId).eq("status", "active").is("revoked_at", null).lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).single();
1089
- if (orgRole?.role === "org_admin") {
1090
- rbacCache.set(cacheKey, "admin", 6e4);
1091
- return "admin";
1092
- }
1093
- }
1094
- if (scope.eventId && scope.appId) {
1095
- const { data: eventRole } = await this.supabase.from("rbac_event_app_roles").select("role").eq("user_id", userId).eq("event_id", scope.eventId).eq("app_id", scope.appId).eq("status", "active").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).single();
1096
- if (eventRole?.role === "event_admin") {
1097
- rbacCache.set(cacheKey, "admin", 6e4);
1098
- return "admin";
1099
- }
1100
- if (eventRole?.role === "planner") {
1101
- rbacCache.set(cacheKey, "planner", 6e4);
1102
- return "planner";
1103
- }
1104
- if (eventRole?.role === "participant") {
1105
- rbacCache.set(cacheKey, "participant", 6e4);
1106
- return "participant";
1107
- }
1108
- }
1109
- rbacCache.set(cacheKey, "viewer", 6e4);
1110
- return "viewer";
1111
- }
1112
- /**
1113
- * Get user's permission map for a scope
1114
- *
1115
- * This builds a map of page IDs to allowed operations.
1116
- * Uses the simplified RPC for each permission check.
1117
- *
1118
- * @param input - Permission map input
1119
- * @returns Promise resolving to permission map
1120
- */
1121
- async getPermissionMap(input) {
1122
- const { userId, scope } = input;
1123
- const cacheKey = RBACCache.generatePermissionMapKey(
1124
- userId,
1125
- scope.organisationId || "",
1126
- scope.eventId,
1127
- scope.appId
1128
- );
1129
- const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1130
- if (isSuperAdmin2) {
1131
- const wildcardMap = { "*": true };
1132
- rbacCache.set(cacheKey, wildcardMap, 6e4);
1133
- return wildcardMap;
1134
- }
1135
- if (!scope.organisationId) {
1136
- return {};
1137
- }
1138
- const cached = rbacCache.get(cacheKey);
1139
- if (cached) {
1140
- return cached;
1141
- }
1142
- const permissionMap = {};
1143
- if (scope.appId) {
1144
- const { data: pages } = await this.supabase.from("rbac_app_pages").select("id, page_name").eq("app_id", scope.appId);
1145
- if (pages) {
1146
- if (!scope.organisationId) {
1147
- rbacCache.set(cacheKey, permissionMap, 6e4);
1148
- return permissionMap;
1149
- }
1150
- const securityContext = {
1151
- userId,
1152
- organisationId: scope.organisationId,
1153
- // Required
1154
- timestamp: /* @__PURE__ */ new Date()
1155
- };
1156
- for (const page of pages) {
1157
- for (const operation of ["read", "create", "update", "delete"]) {
1158
- const permissionString = `${operation}:page.${page.page_name}`;
1159
- const hasPermission2 = await this.isPermitted(
1160
- {
1161
- userId,
1162
- scope,
1163
- permission: permissionString,
1164
- pageId: page.id
1165
- },
1166
- securityContext
1167
- );
1168
- const permissionKey = permissionString;
1169
- permissionMap[permissionKey] = hasPermission2;
1170
- }
1171
- }
1172
- }
1173
- }
1174
- rbacCache.set(cacheKey, permissionMap, 6e4);
1175
- return permissionMap;
1176
- }
1177
- async resolveAppContext(input) {
1178
- try {
1179
- const { userId, appName } = input;
1180
- const { data, error } = await this.supabase.rpc("util_app_resolve", {
1181
- p_user_id: userId,
1182
- p_app_name: appName
1183
- });
1184
- if (error) {
1185
- console.error("[RBACEngine] Failed to resolve app context:", error);
1186
- return null;
1187
- }
1188
- if (!data || data.length === 0) {
1189
- return null;
1190
- }
1191
- const appData = data[0];
1192
- if (!appData?.app_id) {
1193
- return null;
1194
- }
1195
- return {
1196
- appId: appData.app_id,
1197
- hasAccess: appData.has_access !== false
1198
- };
1199
- } catch (error) {
1200
- console.error("[RBACEngine] Unexpected error resolving app context:", error);
1201
- return null;
1202
- }
1203
- }
1204
- async getRoleContext(input) {
1205
- const result = {
1206
- globalRole: null,
1207
- organisationRole: null,
1208
- eventAppRole: null
1209
- };
1210
- try {
1211
- const { userId, scope } = input;
1212
- const { data, error } = await this.supabase.rpc("rbac_permissions_get", {
1213
- p_user_id: userId,
1214
- p_organisation_id: scope.organisationId || null,
1215
- p_event_id: scope.eventId || null,
1216
- p_app_id: scope.appId || null,
1217
- p_page_id: null
1218
- // Optional: can filter to specific page if needed
1219
- });
1220
- if (error) {
1221
- console.error("[RBACEngine] Failed to load role context:", error);
1222
- return result;
1223
- }
1224
- if (!Array.isArray(data)) {
1225
- return result;
1226
- }
1227
- for (const permission of data) {
1228
- if (permission.permission_type === "all_permissions") {
1229
- result.globalRole = "super_admin";
1230
- }
1231
- if (permission.permission_type === "organisation_access") {
1232
- result.organisationRole = permission.role_name;
1233
- }
1234
- if (permission.permission_type === "event_app_access") {
1235
- result.eventAppRole = permission.role_name;
1236
- }
1237
- }
1238
- return result;
1239
- } catch (error) {
1240
- console.error("[RBACEngine] Unexpected error loading role context:", error);
1241
- return result;
1242
- }
1243
- }
1244
- /**
1245
- * Check if user is super admin
1246
- *
1247
- * @param userId - User ID
1248
- * @returns Promise resolving to super admin status
1249
- */
1250
- async checkSuperAdmin(userId) {
1251
- const cacheKey = `super_admin:${userId}`;
1252
- const cached = rbacCache.get(cacheKey);
1253
- if (cached !== null) {
1254
- return cached;
1255
- }
1256
- const now = (/* @__PURE__ */ new Date()).toISOString();
1257
- const { data, error } = await this.supabase.from("rbac_global_roles").select("role").eq("user_id", userId).eq("role", "super_admin").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).limit(1);
1258
- const isSuperAdmin2 = !error && data && data.length > 0;
1259
- rbacCache.set(cacheKey, isSuperAdmin2, 6e4);
1260
- return Boolean(isSuperAdmin2);
1261
- }
1262
- /**
1263
- * Resolve a page ID to UUID if it's a page name
1264
- *
1265
- * @param pageId - Page ID (UUID) or page name (string)
1266
- * @param appId - App ID to look up the page
1267
- * @returns Resolved page ID (UUID) or original pageId
1268
- */
1269
- async resolvePageId(pageId, appId) {
1270
- if (!pageId) {
1271
- return void 0;
1272
- }
1273
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1274
- if (uuidRegex.test(pageId)) {
1275
- return pageId;
1276
- }
1277
- if (!appId) {
1278
- return pageId;
1279
- }
1280
- try {
1281
- const { data: page } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).single();
1282
- return page?.id || pageId;
1283
- } catch (error) {
1284
- console.warn("[RBAC Engine] Failed to resolve page name to UUID:", { pageId, appId, error });
1285
- return pageId;
1286
- }
1287
- }
1288
- };
1289
- function createRBACEngine(supabase, securityConfig) {
1290
- return new RBACEngine(supabase, securityConfig);
1291
- }
1292
-
1293
- // src/rbac/config.ts
1294
- var RBACConfigManager = class {
1295
- constructor() {
1296
- this.config = null;
1297
- this.logger = null;
1298
- }
1299
- setConfig(config) {
1300
- this.config = config;
1301
- this.setupLogger();
1302
- }
1303
- getConfig() {
1304
- return this.config;
1305
- }
1306
- getLogger() {
1307
- if (!this.logger) {
1308
- this.logger = this.createDefaultLogger();
1309
- }
1310
- return this.logger;
1311
- }
1312
- setupLogger() {
1313
- if (!this.config) return;
1314
- const { debug = false, logLevel = "warn" } = this.config;
1315
- this.logger = {
1316
- error: (message, ...args) => {
1317
- console.error(`[RBAC ERROR] ${message}`, ...args);
1318
- },
1319
- warn: (message, ...args) => {
1320
- if (logLevel === "warn" || logLevel === "info" || logLevel === "debug") {
1321
- console.warn(`[RBAC WARN] ${message}`, ...args);
1322
- }
1323
- },
1324
- info: (message, ...args) => {
1325
- if (logLevel === "info" || logLevel === "debug") {
1326
- console.info(`[RBAC INFO] ${message}`, ...args);
1327
- }
1328
- },
1329
- debug: (message, ...args) => {
1330
- if (debug && logLevel === "debug") {
1331
- console.debug(`[RBAC DEBUG] ${message}`, ...args);
1332
- }
1333
- }
1334
- };
1335
- }
1336
- createDefaultLogger() {
1337
- return {
1338
- error: (message, ...args) => console.error(`[RBAC ERROR] ${message}`, ...args),
1339
- warn: (message, ...args) => console.warn(`[RBAC WARN] ${message}`, ...args),
1340
- info: (message, ...args) => console.info(`[RBAC INFO] ${message}`, ...args),
1341
- debug: (message, ...args) => console.debug(`[RBAC DEBUG] ${message}`, ...args)
1342
- };
1343
- }
1344
- isDebugMode() {
1345
- return this.config?.debug ?? false;
1346
- }
1347
- isDevelopmentMode() {
1348
- return this.config?.developmentMode ?? false;
1349
- }
1350
- getMockPermissions() {
1351
- return this.config?.mockPermissions ?? null;
1352
- }
1353
- };
1354
- var configManager = new RBACConfigManager();
1355
- function createRBACConfig(config) {
1356
- configManager.setConfig(config);
1357
- return config;
1358
- }
1359
- function getRBACConfig() {
1360
- return configManager.getConfig();
1361
- }
1362
- function getRBACLogger() {
1363
- return configManager.getLogger();
1364
- }
1365
- function isDebugMode() {
1366
- return configManager.isDebugMode();
1367
- }
1368
- function isDevelopmentMode() {
1369
- return configManager.isDevelopmentMode();
1370
- }
1371
-
1372
- // src/rbac/api.ts
1373
- var globalEngine = null;
1374
- function setupRBAC(supabase, config) {
1375
- const logger = getRBACLogger();
1376
- const fullConfig = {
1377
- supabase,
1378
- debug: import.meta.env.MODE === "development",
1379
- logLevel: "warn",
1380
- developmentMode: import.meta.env.MODE === "development",
1381
- ...config
1382
- };
1383
- createRBACConfig(fullConfig);
1384
- globalEngine = createRBACEngine(supabase, config?.security);
1385
- const auditManager = createAuditManager(supabase);
1386
- setGlobalAuditManager(auditManager);
1387
- logger.info("RBAC system initialized successfully");
1388
- }
1389
- function getEngine() {
1390
- if (!globalEngine) {
1391
- throw new RBACNotInitializedError();
1392
- }
1393
- return globalEngine;
1394
- }
1395
- async function getAccessLevel(input) {
1396
- const engine = getEngine();
1397
- return engine.getAccessLevel(input);
1398
- }
1399
- async function getPermissionMap(input) {
1400
- const engine = getEngine();
1401
- return engine.getPermissionMap(input);
1402
- }
1403
- async function resolveAppContext(input) {
1404
- const engine = getEngine();
1405
- return engine.resolveAppContext(input);
1406
- }
1407
- async function getRoleContext(input) {
1408
- const engine = getEngine();
1409
- return engine.getRoleContext(input);
1410
- }
1411
- async function isPermitted(input) {
1412
- const engine = getEngine();
1413
- if (!input.scope.organisationId) {
1414
- throw new OrganisationContextRequiredError();
1415
- }
1416
- const securityContext = {
1417
- userId: input.userId,
1418
- organisationId: input.scope.organisationId,
1419
- // Required - no fallback
1420
- timestamp: /* @__PURE__ */ new Date()
1421
- // Optional fields can be omitted
1422
- };
1423
- return engine.isPermitted(input, securityContext);
1424
- }
1425
- async function isPermittedCached(input) {
1426
- const { userId, scope, permission, pageId } = input;
1427
- const cacheKey = RBACCache.generatePermissionKey({
1428
- userId,
1429
- organisationId: scope.organisationId,
1430
- eventId: scope.eventId,
1431
- appId: scope.appId,
1432
- permission,
1433
- pageId
1434
- });
1435
- const cached = rbacCache.get(cacheKey);
1436
- if (cached !== null) {
1437
- return cached;
1438
- }
1439
- const result = await isPermitted(input);
1440
- rbacCache.set(cacheKey, result);
1441
- return result;
1442
- }
1443
- async function hasPermission(input) {
1444
- return isPermitted(input);
1445
- }
1446
- async function hasAnyPermission(input) {
1447
- const { permissions, ...baseInput } = input;
1448
- for (const permission of permissions) {
1449
- const hasPermission2 = await isPermitted({
1450
- ...baseInput,
1451
- permission
1452
- });
1453
- if (hasPermission2) {
1454
- return true;
1455
- }
1456
- }
1457
- return false;
1458
- }
1459
- async function hasAllPermissions(input) {
1460
- const { permissions, ...baseInput } = input;
1461
- for (const permission of permissions) {
1462
- const hasPermission2 = await isPermitted({
1463
- ...baseInput,
1464
- permission
1465
- });
1466
- if (!hasPermission2) {
1467
- return false;
1468
- }
1469
- }
1470
- return true;
1471
- }
1472
- async function isSuperAdmin(userId) {
1473
- const engine = getEngine();
1474
- return engine["checkSuperAdmin"](userId);
1475
- }
1476
- async function getAppConfig(appId) {
1477
- console.warn("[RBAC] getAppConfig called without Supabase client - returning null");
1478
- return null;
1479
- }
1480
- async function getAppConfigWithClient(client, appId) {
1481
- try {
1482
- const { data, error } = await client.from("rbac_apps").select("requires_event").eq("id", appId).eq("is_active", true).single();
1483
- if (error || !data) {
1484
- return null;
1485
- }
1486
- return { requires_event: data.requires_event };
1487
- } catch (err) {
1488
- console.error("[RBAC] Error fetching app config:", err);
1489
- return null;
1490
- }
1491
- }
1492
- async function isOrganisationAdmin(userId, organisationId) {
1493
- const accessLevel = await getAccessLevel({
1494
- userId,
1495
- scope: { organisationId }
1496
- });
1497
- return accessLevel === "admin" || accessLevel === "super";
1498
- }
1499
- async function isEventAdmin(userId, scope) {
1500
- if (!scope.eventId || !scope.appId) {
1501
- return false;
1502
- }
1503
- const accessLevel = await getAccessLevel({ userId, scope });
1504
- return accessLevel === "admin" || accessLevel === "super";
1505
- }
1506
- function invalidateUserCache(userId, organisationId) {
1507
- const patterns = organisationId ? [
1508
- CACHE_PATTERNS.PERMISSION(userId, organisationId),
1509
- `access:${userId}:${organisationId}:`,
1510
- `map:${userId}:${organisationId}:`
1511
- ] : [
1512
- `perm:${userId}:`,
1513
- `access:${userId}:`,
1514
- `map:${userId}:`
1515
- ];
1516
- patterns.forEach((pattern) => rbacCache.invalidate(pattern));
1517
- }
1518
- function invalidateOrganisationCache(organisationId) {
1519
- rbacCache.invalidate(CACHE_PATTERNS.ORGANISATION(organisationId));
1520
- }
1521
- function invalidateEventCache(eventId) {
1522
- rbacCache.invalidate(CACHE_PATTERNS.EVENT(eventId));
1523
- }
1524
- function invalidateAppCache(appId) {
1525
- rbacCache.invalidate(CACHE_PATTERNS.APP(appId));
1526
- }
1527
- function clearCache() {
1528
- rbacCache.clear();
1529
- }
1530
-
1531
- export {
1532
- createRBACConfig,
1533
- getRBACConfig,
1534
- getRBACLogger,
1535
- isDebugMode,
1536
- isDevelopmentMode,
1537
- OrganisationContextRequiredError,
1538
- RBACCache,
1539
- rbacCache,
1540
- CACHE_PATTERNS,
1541
- RBACEngine,
1542
- createRBACEngine,
1543
- setupRBAC,
1544
- getAccessLevel,
1545
- getPermissionMap,
1546
- resolveAppContext,
1547
- getRoleContext,
1548
- isPermitted,
1549
- isPermittedCached,
1550
- hasPermission,
1551
- hasAnyPermission,
1552
- hasAllPermissions,
1553
- isSuperAdmin,
1554
- getAppConfig,
1555
- getAppConfigWithClient,
1556
- isOrganisationAdmin,
1557
- isEventAdmin,
1558
- invalidateUserCache,
1559
- invalidateOrganisationCache,
1560
- invalidateEventCache,
1561
- invalidateAppCache,
1562
- clearCache
1563
- };
1564
- //# sourceMappingURL=chunk-WP5I5GLN.js.map