@jmruthers/pace-core 0.5.74 → 0.5.75

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 (278) hide show
  1. package/dist/{DataTable-2QR5TER5.js → DataTable-HWZQGASI.js} +8 -8
  2. package/dist/{PublicLoadingSpinner-DLpF5bbs.d.ts → PublicLoadingSpinner-BKNBT6b6.d.ts} +2 -2
  3. package/dist/RBACService-C4udt_Zp.d.ts +528 -0
  4. package/dist/{UnifiedAuthProvider-K4NRGXL4.js → UnifiedAuthProvider-3NKDOSOK.js} +6 -4
  5. package/dist/UnifiedAuthProvider-Bj6YCf7c.d.ts +113 -0
  6. package/dist/{chunk-UJMCGBLS.js → chunk-2CHATWBF.js} +5 -7
  7. package/dist/chunk-2CHATWBF.js.map +1 -0
  8. package/dist/{chunk-BKVGJVUR.js → chunk-2DFZ432F.js} +496 -30
  9. package/dist/chunk-2DFZ432F.js.map +1 -0
  10. package/dist/{chunk-LVQ26TCN.js → chunk-33PHABLB.js} +36 -3
  11. package/dist/chunk-33PHABLB.js.map +1 -0
  12. package/dist/chunk-5F3NDPJV.js +232 -0
  13. package/dist/chunk-5F3NDPJV.js.map +1 -0
  14. package/dist/chunk-A4FUBC7B.js +17 -0
  15. package/dist/chunk-A4FUBC7B.js.map +1 -0
  16. package/dist/{chunk-SMJZMKYN.js → chunk-A6HBIY5P.js} +2 -11
  17. package/dist/{chunk-SMJZMKYN.js.map → chunk-A6HBIY5P.js.map} +1 -1
  18. package/dist/{chunk-IHMMNKNA.js → chunk-CY3AHGO4.js} +6256 -1937
  19. package/dist/chunk-CY3AHGO4.js.map +1 -0
  20. package/dist/{chunk-H2TNUICK.js → chunk-DAXLNIDY.js} +47 -49
  21. package/dist/chunk-DAXLNIDY.js.map +1 -0
  22. package/dist/{chunk-VKOCWWVY.js → chunk-L3RV2ALE.js} +1 -6
  23. package/dist/{chunk-VKOCWWVY.js.map → chunk-L3RV2ALE.js.map} +1 -1
  24. package/dist/chunk-LW7MMEAQ.js +59 -0
  25. package/dist/chunk-LW7MMEAQ.js.map +1 -0
  26. package/dist/{chunk-DG5Z55HH.js → chunk-NTNILOBC.js} +7 -9
  27. package/dist/chunk-NTNILOBC.js.map +1 -0
  28. package/dist/chunk-PYUXFQJ3.js +11 -0
  29. package/dist/chunk-PYUXFQJ3.js.map +1 -0
  30. package/dist/chunk-URUTVZ7N.js +27 -0
  31. package/dist/chunk-URUTVZ7N.js.map +1 -0
  32. package/dist/chunk-WN6XJWOS.js +2468 -0
  33. package/dist/chunk-WN6XJWOS.js.map +1 -0
  34. package/dist/{chunk-3SP4P7NS.js → chunk-XLZ7U46Z.js} +59 -1
  35. package/dist/chunk-XLZ7U46Z.js.map +1 -0
  36. package/dist/{chunk-ORSMVXO2.js → chunk-ZTT2AXMX.js} +9 -14
  37. package/dist/chunk-ZTT2AXMX.js.map +1 -0
  38. package/dist/components.d.ts +4 -5
  39. package/dist/components.js +32 -39
  40. package/dist/components.js.map +1 -1
  41. package/dist/hooks.d.ts +3 -3
  42. package/dist/hooks.js +9 -8
  43. package/dist/hooks.js.map +1 -1
  44. package/dist/index.d.ts +156 -10
  45. package/dist/index.js +188 -93
  46. package/dist/index.js.map +1 -1
  47. package/dist/{organisation-t-vvQC3g.d.ts → organisation-BtshODVF.d.ts} +4 -3
  48. package/dist/providers.d.ts +27 -38
  49. package/dist/providers.js +33 -23
  50. package/dist/rbac/index.d.ts +61 -5
  51. package/dist/rbac/index.js +13 -14
  52. package/dist/styles/index.js +2 -2
  53. package/dist/theming/runtime.js +1 -3
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +1 -1
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CMPjE_fv.d.ts → unified-CM7T0aTK.d.ts} +1 -1
  58. package/dist/useInactivityTracker-MRUU55XI.js +10 -0
  59. package/dist/useInactivityTracker-MRUU55XI.js.map +1 -0
  60. package/dist/{usePublicRouteParams-Ua1Vz-HG.d.ts → usePublicRouteParams-B-CumWRc.d.ts} +3 -3
  61. package/dist/utils.js +7 -9
  62. package/dist/utils.js.map +1 -1
  63. package/dist/validation.d.ts +1 -1
  64. package/docs/api/classes/ColumnFactory.md +1 -1
  65. package/docs/api/classes/ErrorBoundary.md +1 -1
  66. package/docs/api/classes/InvalidScopeError.md +1 -1
  67. package/docs/api/classes/MissingUserContextError.md +1 -1
  68. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  69. package/docs/api/classes/PermissionDeniedError.md +1 -1
  70. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  71. package/docs/api/classes/RBACAuditManager.md +1 -1
  72. package/docs/api/classes/RBACCache.md +1 -1
  73. package/docs/api/classes/RBACEngine.md +1 -1
  74. package/docs/api/classes/RBACError.md +1 -1
  75. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  76. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  77. package/docs/api/classes/StorageUtils.md +1 -1
  78. package/docs/api/enums/FileCategory.md +1 -1
  79. package/docs/api/interfaces/AggregateConfig.md +1 -1
  80. package/docs/api/interfaces/ButtonProps.md +3 -3
  81. package/docs/api/interfaces/CardProps.md +2 -2
  82. package/docs/api/interfaces/ColorPalette.md +1 -1
  83. package/docs/api/interfaces/ColorShade.md +1 -1
  84. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  85. package/docs/api/interfaces/DataTableAction.md +1 -1
  86. package/docs/api/interfaces/DataTableColumn.md +1 -1
  87. package/docs/api/interfaces/DataTableProps.md +1 -1
  88. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  89. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  90. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  91. package/docs/api/interfaces/EventLogoProps.md +2 -2
  92. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  93. package/docs/api/interfaces/FileMetadata.md +1 -1
  94. package/docs/api/interfaces/FileReference.md +1 -1
  95. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  96. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  97. package/docs/api/interfaces/FileUploadProps.md +1 -1
  98. package/docs/api/interfaces/FooterProps.md +1 -1
  99. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  100. package/docs/api/interfaces/InputProps.md +2 -2
  101. package/docs/api/interfaces/LabelProps.md +1 -1
  102. package/docs/api/interfaces/LoginFormProps.md +1 -1
  103. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  104. package/docs/api/interfaces/NavigationContextType.md +1 -1
  105. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  106. package/docs/api/interfaces/NavigationItem.md +1 -1
  107. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  108. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  109. package/docs/api/interfaces/Organisation.md +1 -1
  110. package/docs/api/interfaces/OrganisationContextType.md +28 -17
  111. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  112. package/docs/api/interfaces/OrganisationProviderProps.md +2 -2
  113. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  114. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  115. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  116. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  117. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  118. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  119. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  120. package/docs/api/interfaces/PaletteData.md +1 -1
  121. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  122. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  123. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  124. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +2 -2
  125. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  126. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  127. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  128. package/docs/api/interfaces/RBACConfig.md +1 -1
  129. package/docs/api/interfaces/RBACContextType.md +5 -11
  130. package/docs/api/interfaces/RBACLogger.md +1 -1
  131. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  132. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  134. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  135. package/docs/api/interfaces/RouteConfig.md +1 -1
  136. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  137. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  138. package/docs/api/interfaces/StorageConfig.md +1 -1
  139. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  140. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  141. package/docs/api/interfaces/StorageListOptions.md +1 -1
  142. package/docs/api/interfaces/StorageListResult.md +1 -1
  143. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  144. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  145. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  146. package/docs/api/interfaces/StyleImport.md +1 -1
  147. package/docs/api/interfaces/SwitchProps.md +1 -1
  148. package/docs/api/interfaces/ToastActionElement.md +1 -1
  149. package/docs/api/interfaces/ToastProps.md +1 -1
  150. package/docs/api/interfaces/UnifiedAuthContextType.md +524 -440
  151. package/docs/api/interfaces/UnifiedAuthProviderProps.md +14 -14
  152. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  153. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  154. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  159. package/docs/api/interfaces/UserEventAccess.md +11 -11
  160. package/docs/api/interfaces/UserMenuProps.md +1 -1
  161. package/docs/api/interfaces/UserProfile.md +1 -1
  162. package/docs/api/modules.md +179 -52
  163. package/docs/architecture/services.md +30 -32
  164. package/docs/breaking-changes.md +2 -5
  165. package/docs/migration/service-architecture.md +121 -260
  166. package/docs/rbac/README-rbac-rls-integration.md +48 -38
  167. package/{src/rbac/examples → examples/RBAC}/CompleteRBACExample.tsx +3 -2
  168. package/{src/rbac/examples → examples/RBAC}/EventBasedApp.tsx +5 -4
  169. package/{src/components/examples → examples/RBAC}/PermissionExample.tsx +7 -6
  170. package/examples/RBAC/__tests__/PermissionExample.test.tsx +150 -0
  171. package/examples/RBAC/index.ts +13 -0
  172. package/examples/README.md +37 -0
  173. package/examples/index.ts +22 -0
  174. package/{src/examples → examples/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  175. package/{src/examples → examples/public-pages}/PublicEventPage.tsx +1 -1
  176. package/{src/examples → examples/public-pages}/PublicPageApp.tsx +1 -1
  177. package/{src/examples → examples/public-pages}/PublicPageUsageExample.tsx +1 -1
  178. package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +159 -0
  179. package/examples/public-pages/index.ts +14 -0
  180. package/package.json +22 -18
  181. package/src/__tests__/TEST_GUIDE_CURSOR.md +650 -9
  182. package/src/__tests__/helpers/README.md +255 -0
  183. package/src/__tests__/helpers/index.ts +62 -0
  184. package/src/__tests__/helpers/supabaseMock.ts +27 -3
  185. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -8
  186. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +55 -0
  187. package/src/components/DataTable/core/ColumnManager.ts +10 -0
  188. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +254 -0
  189. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +193 -0
  190. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +45 -0
  191. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +117 -0
  192. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +71 -0
  193. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +122 -0
  194. package/src/components/EventSelector/EventSelector.tsx +1 -1
  195. package/src/components/Header/Header.test.tsx +35 -1
  196. package/src/components/Header/Header.tsx +3 -1
  197. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -3
  198. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +24 -4
  199. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +3 -2
  200. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +220 -0
  201. package/src/hooks/__tests__/useIsMobile.unit.test.ts +117 -0
  202. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +295 -0
  203. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +29 -19
  204. package/src/hooks/__tests__/useRBAC.unit.test.ts +7 -3
  205. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +115 -19
  206. package/src/hooks/useEventTheme.test.ts +350 -0
  207. package/src/hooks/useEventTheme.ts +1 -1
  208. package/src/hooks/useEvents.ts +61 -0
  209. package/src/hooks/useOrganisationSecurity.test.ts +4 -4
  210. package/src/hooks/useOrganisationSecurity.ts +2 -2
  211. package/src/hooks/useOrganisations.ts +64 -0
  212. package/src/hooks/useSecureDataAccess.test.ts +9 -5
  213. package/src/hooks/useSecureDataAccess.ts +2 -2
  214. package/src/index.ts +18 -3
  215. package/src/providers/AuthProvider.tsx +8 -292
  216. package/src/providers/EventProvider.tsx +15 -425
  217. package/src/providers/InactivityProvider.tsx +8 -231
  218. package/src/providers/OrganisationProvider.test.simple.tsx +3 -2
  219. package/src/providers/OrganisationProvider.tsx +11 -890
  220. package/src/providers/UnifiedAuthProvider.tsx +8 -320
  221. package/src/providers/__tests__/AuthProvider.test.tsx +18 -17
  222. package/src/providers/__tests__/EventProvider.test.tsx +253 -2
  223. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +65 -0
  224. package/src/providers/__tests__/InactivityProvider.test.tsx +46 -114
  225. package/src/providers/__tests__/OrganisationProvider.test.tsx +313 -3
  226. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +383 -2
  227. package/src/providers/index.ts +8 -7
  228. package/src/providers/services/EventServiceProvider.tsx +3 -0
  229. package/src/providers/services/UnifiedAuthProvider.tsx +3 -0
  230. package/src/rbac/hooks/usePermissions.test.ts +296 -0
  231. package/src/rbac/hooks/useRBAC.test.ts +9 -5
  232. package/src/rbac/hooks/useRBAC.ts +3 -3
  233. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +688 -0
  234. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +507 -0
  235. package/src/services/AuthService.ts +19 -4
  236. package/src/services/__tests__/AuthService.test.ts +288 -0
  237. package/src/styles/core.css +2 -0
  238. package/src/types/__tests__/guards.test.ts +246 -0
  239. package/src/types/guards.ts +1 -0
  240. package/src/types/organisation.ts +3 -2
  241. package/src/validation/__tests__/sanitization.unit.test.ts +250 -0
  242. package/src/validation/__tests__/schemaUtils.unit.test.ts +451 -0
  243. package/src/validation/__tests__/user.unit.test.ts +440 -0
  244. package/dist/RBACProvider-BO4ilsQB.d.ts +0 -63
  245. package/dist/UnifiedAuthProvider-D02AMXgO.d.ts +0 -103
  246. package/dist/chunk-3SP4P7NS.js.map +0 -1
  247. package/dist/chunk-B5LK25HV.js +0 -953
  248. package/dist/chunk-B5LK25HV.js.map +0 -1
  249. package/dist/chunk-BKVGJVUR.js.map +0 -1
  250. package/dist/chunk-C5Q5LRU5.js +0 -5691
  251. package/dist/chunk-C5Q5LRU5.js.map +0 -1
  252. package/dist/chunk-CDDYJCYU.js +0 -79
  253. package/dist/chunk-CDDYJCYU.js.map +0 -1
  254. package/dist/chunk-DG5Z55HH.js.map +0 -1
  255. package/dist/chunk-H2TNUICK.js.map +0 -1
  256. package/dist/chunk-IHMMNKNA.js.map +0 -1
  257. package/dist/chunk-LVQ26TCN.js.map +0 -1
  258. package/dist/chunk-ORSMVXO2.js.map +0 -1
  259. package/dist/chunk-UJMCGBLS.js.map +0 -1
  260. package/dist/chunk-V6BHACCH.js +0 -17
  261. package/dist/chunk-V6BHACCH.js.map +0 -1
  262. package/dist/rbac/cli/policy-manager.js +0 -278
  263. package/dist/rbac/cli/policy-manager.js.map +0 -1
  264. package/docs/api/interfaces/EventContextType.md +0 -96
  265. package/docs/api/interfaces/EventProviderProps.md +0 -19
  266. package/src/providers/OrganisationProvider.test.tsx +0 -164
  267. package/src/providers/UnifiedAuthProvider.test.tsx +0 -124
  268. package/src/providers/__tests__/AuthProvider.test.tsx.backup +0 -771
  269. package/src/providers/__tests__/EventProvider.test.tsx.backup +0 -824
  270. package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +0 -820
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +0 -911
  272. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +0 -166
  273. package/src/rbac/cli/__tests__/policy-manager.test.ts +0 -339
  274. package/src/rbac/cli/policy-manager.ts +0 -443
  275. package/dist/{DataTable-2QR5TER5.js.map → DataTable-HWZQGASI.js.map} +0 -0
  276. package/dist/{UnifiedAuthProvider-K4NRGXL4.js.map → UnifiedAuthProvider-3NKDOSOK.js.map} +0 -0
  277. package/dist/{validation-PM_iOaTI.d.ts → validation-D8VcbTzC.d.ts} +2 -2
  278. /package/src/utils/{appNameResolver.test.ts.backup → appNameResolver.test 2.ts} +0 -0
@@ -1,278 +0,0 @@
1
- #!/usr/bin/env node
2
- import "../../chunk-PLDDJCW6.js";
3
-
4
- // src/rbac/cli/policy-manager.ts
5
- import { createClient } from "@supabase/supabase-js";
6
- import { Command } from "commander";
7
- import chalk from "chalk";
8
- import ora from "ora";
9
- import Table from "cli-table3";
10
- var PolicyManager = class {
11
- constructor(url, key) {
12
- this.supabase = createClient(url, key);
13
- }
14
- /**
15
- * List all registered tables
16
- */
17
- async listTables() {
18
- const spinner = ora("Fetching registered tables...").start();
19
- try {
20
- const { data, error } = await this.supabase.from("rbac_policy_configs").select("*").eq("is_active", true).order("table_name");
21
- if (error) throw error;
22
- spinner.succeed("Fetched registered tables");
23
- if (data.length === 0) {
24
- console.log(chalk.yellow("No tables registered for RBAC policy management."));
25
- return;
26
- }
27
- const table = new Table({
28
- head: ["Table", "Page", "App", "Org Column", "Event Column", "Operations"],
29
- colWidths: [20, 15, 10, 15, 15, 30]
30
- });
31
- data.forEach((config) => {
32
- table.push([
33
- config.table_name,
34
- config.page_name,
35
- config.app_name,
36
- config.organisation_column,
37
- config.event_column || "N/A",
38
- config.operations.join(", ")
39
- ]);
40
- });
41
- console.log(table.toString());
42
- } catch (error) {
43
- spinner.fail("Failed to fetch tables");
44
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
45
- }
46
- }
47
- /**
48
- * Register a new table for RBAC policy management
49
- */
50
- async registerTable(tableName, pageName, appName = "CAKE", orgColumn = "organisation_id", eventColumn, operations = ["read", "create", "update", "delete"]) {
51
- const spinner = ora(`Registering table ${tableName}...`).start();
52
- try {
53
- const { data, error } = await this.supabase.rpc("register_rbac_table", {
54
- p_table_name: tableName,
55
- p_page_name: pageName,
56
- p_app_name: appName,
57
- p_organisation_column: orgColumn,
58
- p_event_column: eventColumn,
59
- p_operations: operations
60
- });
61
- if (error) throw error;
62
- if (data) {
63
- spinner.succeed(`Successfully registered table ${tableName}`);
64
- } else {
65
- spinner.fail(`Failed to register table ${tableName}`);
66
- }
67
- } catch (error) {
68
- spinner.fail(`Failed to register table ${tableName}`);
69
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
70
- }
71
- }
72
- /**
73
- * Update policies for a specific table
74
- */
75
- async updateTable(tableName, pageName, appName = "CAKE") {
76
- const spinner = ora(`Updating policies for ${tableName}...`).start();
77
- try {
78
- const { data, error } = await this.supabase.rpc("update_rbac_policies_for_table", {
79
- p_table_name: tableName,
80
- p_page_name: pageName,
81
- p_app_name: appName
82
- });
83
- if (error) throw error;
84
- if (data) {
85
- spinner.succeed(`Successfully updated policies for ${tableName}`);
86
- } else {
87
- spinner.fail(`Failed to update policies for ${tableName}`);
88
- }
89
- } catch (error) {
90
- spinner.fail(`Failed to update policies for ${tableName}`);
91
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
92
- }
93
- }
94
- /**
95
- * Update all RBAC policies
96
- */
97
- async updateAll() {
98
- const spinner = ora("Updating all RBAC policies...").start();
99
- try {
100
- const { data, error } = await this.supabase.rpc("update_all_rbac_policies");
101
- if (error) throw error;
102
- spinner.succeed("Updated all RBAC policies");
103
- const table = new Table({
104
- head: ["Table", "Page", "App", "Success", "Error"],
105
- colWidths: [20, 15, 10, 10, 30]
106
- });
107
- data.forEach((result) => {
108
- table.push([
109
- result.table_name,
110
- result.page_name,
111
- result.app_name,
112
- result.success ? chalk.green("\u2713") : chalk.red("\u2717"),
113
- result.error_message || ""
114
- ]);
115
- });
116
- console.log(table.toString());
117
- } catch (error) {
118
- spinner.fail("Failed to update all policies");
119
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
120
- }
121
- }
122
- /**
123
- * Check policy health
124
- */
125
- async checkHealth() {
126
- const spinner = ora("Checking policy health...").start();
127
- try {
128
- const { data, error } = await this.supabase.rpc("check_rbac_policy_health");
129
- if (error) throw error;
130
- spinner.succeed("Policy health check complete");
131
- if (data.length === 0) {
132
- console.log(chalk.yellow("No policies found."));
133
- return;
134
- }
135
- const healthyPolicies = data.filter((h) => h.is_healthy);
136
- const unhealthyPolicies = data.filter((h) => !h.is_healthy);
137
- console.log(chalk.green(`\u2713 ${healthyPolicies.length} healthy policies`));
138
- console.log(chalk.red(`\u2717 ${unhealthyPolicies.length} unhealthy policies`));
139
- if (unhealthyPolicies.length > 0) {
140
- console.log("\n" + chalk.red("Unhealthy Policies:"));
141
- const table = new Table({
142
- head: ["Table", "Policy", "Operation", "Issues"],
143
- colWidths: [20, 25, 10, 40]
144
- });
145
- unhealthyPolicies.forEach((policy) => {
146
- table.push([
147
- policy.table_name,
148
- policy.policy_name,
149
- policy.operation,
150
- policy.issues.join(", ")
151
- ]);
152
- });
153
- console.log(table.toString());
154
- }
155
- } catch (error) {
156
- spinner.fail("Failed to check policy health");
157
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
158
- }
159
- }
160
- /**
161
- * Show policy audit log
162
- */
163
- async showAudit(limit = 20) {
164
- const spinner = ora("Fetching audit log...").start();
165
- try {
166
- const { data, error } = await this.supabase.from("rbac_policy_audit").select("*").order("changed_at", { ascending: false }).limit(limit);
167
- if (error) throw error;
168
- spinner.succeed("Fetched audit log");
169
- if (data.length === 0) {
170
- console.log(chalk.yellow("No audit entries found."));
171
- return;
172
- }
173
- const table = new Table({
174
- head: ["Table", "Policy", "Operation", "Action", "Success", "Changed At"],
175
- colWidths: [15, 20, 10, 10, 8, 20]
176
- });
177
- data.forEach((audit) => {
178
- table.push([
179
- audit.table_name,
180
- audit.policy_name,
181
- audit.operation,
182
- audit.action,
183
- audit.success ? chalk.green("\u2713") : chalk.red("\u2717"),
184
- new Date(audit.changed_at).toLocaleString()
185
- ]);
186
- });
187
- console.log(table.toString());
188
- } catch (error) {
189
- spinner.fail("Failed to fetch audit log");
190
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
191
- }
192
- }
193
- /**
194
- * Test permission check
195
- */
196
- async testPermission(operation, pageName, orgId, eventId, appName = "CAKE") {
197
- const spinner = ora("Testing permission check...").start();
198
- try {
199
- const { data, error } = await this.supabase.rpc("check_rbac_permission_with_context", {
200
- p_operation: operation,
201
- p_page_name: pageName,
202
- p_resource_organisation_id: orgId,
203
- p_resource_event_id: eventId,
204
- p_app_name: appName
205
- });
206
- if (error) throw error;
207
- spinner.succeed("Permission check complete");
208
- const result = data ? chalk.green("ALLOWED") : chalk.red("DENIED");
209
- console.log(`Permission: ${operation} on ${pageName} = ${result}`);
210
- } catch (error) {
211
- spinner.fail("Failed to test permission");
212
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
213
- }
214
- }
215
- };
216
- var program = new Command();
217
- program.name("rbac-policy-manager").description("CLI tool for managing RBAC-RLS integration policies").version("1.0.0");
218
- program.option("-u, --url <url>", "Supabase URL", process.env.SUPABASE_URL).option("-k, --key <key>", "Supabase service key", process.env.SUPABASE_SERVICE_ROLE_KEY).option("--verbose", "Enable verbose output");
219
- program.command("list").description("List all registered tables").action(async (options) => {
220
- const url = options.parent?.url || process.env.SUPABASE_URL;
221
- const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
222
- const manager = new PolicyManager(url, key);
223
- await manager.listTables();
224
- });
225
- program.command("register <tableName> <pageName>").description("Register a table for RBAC policy management").option("-a, --app <appName>", "App name", "CAKE").option("-o, --org-column <column>", "Organisation column name", "organisation_id").option("-e, --event-column <column>", "Event column name").option("--operations <operations>", "Comma-separated operations", "read,create,update,delete").action(async (tableName, pageName, options) => {
226
- const operations = options.operations.split(",").map((op) => op.trim());
227
- const url = options.parent?.url || process.env.SUPABASE_URL;
228
- const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
229
- const manager = new PolicyManager(url, key);
230
- await manager.registerTable(
231
- tableName,
232
- pageName,
233
- options.app,
234
- options.orgColumn,
235
- options.eventColumn,
236
- operations
237
- );
238
- });
239
- program.command("update <tableName> <pageName>").description("Update policies for a specific table").option("-a, --app <appName>", "App name", "CAKE").action(async (tableName, pageName, options) => {
240
- const url = options.parent?.url || process.env.SUPABASE_URL;
241
- const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
242
- const manager = new PolicyManager(url, key);
243
- await manager.updateTable(tableName, pageName, options.app);
244
- });
245
- program.command("update-all").description("Update all RBAC policies").action(async (options) => {
246
- const url = options.url || process.env.SUPABASE_URL;
247
- const key = options.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
248
- const manager = new PolicyManager(url, key);
249
- await manager.updateAll();
250
- });
251
- program.command("health").description("Check policy health").action(async (options) => {
252
- const url = options.url || process.env.SUPABASE_URL;
253
- const key = options.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
254
- const manager = new PolicyManager(url, key);
255
- await manager.checkHealth();
256
- });
257
- program.command("audit").description("Show policy audit log").option("-l, --limit <number>", "Number of entries to show", "20").action(async (options) => {
258
- const url = options.parent?.url || process.env.SUPABASE_URL;
259
- const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
260
- const manager = new PolicyManager(url, key);
261
- await manager.showAudit(parseInt(options.limit));
262
- });
263
- program.command("test <operation> <pageName> <orgId>").description("Test a permission check").option("-e, --event-id <eventId>", "Event ID").option("-a, --app <appName>", "App name", "CAKE").action(async (operation, pageName, orgId, options) => {
264
- const url = options.parent?.url || process.env.SUPABASE_URL;
265
- const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;
266
- const manager = new PolicyManager(url, key);
267
- await manager.testPermission(operation, pageName, orgId, options.eventId, options.app);
268
- });
269
- program.parse(process.argv);
270
- if (!process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_ROLE_KEY) {
271
- console.error(chalk.red("Error: Missing required environment variables"));
272
- console.error("Please set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY");
273
- process.exit(1);
274
- }
275
- export {
276
- PolicyManager
277
- };
278
- //# sourceMappingURL=policy-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/rbac/cli/policy-manager.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * RBAC Policy Manager CLI Tool\n * \n * This tool provides command-line interface for managing RBAC-RLS integration policies.\n * It allows developers and administrators to easily manage dynamic permission policies.\n */\n\nimport { createClient } from '@supabase/supabase-js';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport Table from 'cli-table3';\n\ninterface PolicyConfig {\n table_name: string;\n page_name: string;\n app_name: string;\n organisation_column: string;\n event_column?: string;\n operations: string[];\n is_active: boolean;\n}\n\ninterface PolicyAudit {\n table_name: string;\n policy_name: string;\n operation: string;\n action: string;\n changed_at: string;\n success: boolean;\n error_message?: string;\n}\n\ninterface HealthCheck {\n table_name: string;\n policy_name: string;\n operation: string;\n is_healthy: boolean;\n issues: string[];\n}\n\nclass PolicyManager {\n private supabase: any;\n\n constructor(url: string, key: string) {\n this.supabase = createClient(url, key);\n }\n\n /**\n * List all registered tables\n */\n async listTables(): Promise<void> {\n const spinner = ora('Fetching registered tables...').start();\n \n try {\n const { data, error } = await this.supabase\n .from('rbac_policy_configs')\n .select('*')\n .eq('is_active', true)\n .order('table_name');\n\n if (error) throw error;\n\n spinner.succeed('Fetched registered tables');\n\n if (data.length === 0) {\n console.log(chalk.yellow('No tables registered for RBAC policy management.'));\n return;\n }\n\n const table = new Table({\n head: ['Table', 'Page', 'App', 'Org Column', 'Event Column', 'Operations'],\n colWidths: [20, 15, 10, 15, 15, 30]\n });\n\n data.forEach((config: PolicyConfig) => {\n table.push([\n config.table_name,\n config.page_name,\n config.app_name,\n config.organisation_column,\n config.event_column || 'N/A',\n config.operations.join(', ')\n ]);\n });\n\n console.log(table.toString());\n } catch (error) {\n spinner.fail('Failed to fetch tables');\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Register a new table for RBAC policy management\n */\n async registerTable(\n tableName: string,\n pageName: string,\n appName: string = 'CAKE',\n orgColumn: string = 'organisation_id',\n eventColumn?: string,\n operations: string[] = ['read', 'create', 'update', 'delete']\n ): Promise<void> {\n const spinner = ora(`Registering table ${tableName}...`).start();\n\n try {\n const { data, error } = await this.supabase\n .rpc('register_rbac_table', {\n p_table_name: tableName,\n p_page_name: pageName,\n p_app_name: appName,\n p_organisation_column: orgColumn,\n p_event_column: eventColumn,\n p_operations: operations\n });\n\n if (error) throw error;\n\n if (data) {\n spinner.succeed(`Successfully registered table ${tableName}`);\n } else {\n spinner.fail(`Failed to register table ${tableName}`);\n }\n } catch (error) {\n spinner.fail(`Failed to register table ${tableName}`);\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Update policies for a specific table\n */\n async updateTable(tableName: string, pageName: string, appName: string = 'CAKE'): Promise<void> {\n const spinner = ora(`Updating policies for ${tableName}...`).start();\n\n try {\n const { data, error } = await this.supabase\n .rpc('update_rbac_policies_for_table', {\n p_table_name: tableName,\n p_page_name: pageName,\n p_app_name: appName\n });\n\n if (error) throw error;\n\n if (data) {\n spinner.succeed(`Successfully updated policies for ${tableName}`);\n } else {\n spinner.fail(`Failed to update policies for ${tableName}`);\n }\n } catch (error) {\n spinner.fail(`Failed to update policies for ${tableName}`);\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Update all RBAC policies\n */\n async updateAll(): Promise<void> {\n const spinner = ora('Updating all RBAC policies...').start();\n\n try {\n const { data, error } = await this.supabase\n .rpc('update_all_rbac_policies');\n\n if (error) throw error;\n\n spinner.succeed('Updated all RBAC policies');\n\n // Display results\n const table = new Table({\n head: ['Table', 'Page', 'App', 'Success', 'Error'],\n colWidths: [20, 15, 10, 10, 30]\n });\n\n data.forEach((result: any) => {\n table.push([\n result.table_name,\n result.page_name,\n result.app_name,\n result.success ? chalk.green('✓') : chalk.red('✗'),\n result.error_message || ''\n ]);\n });\n\n console.log(table.toString());\n } catch (error) {\n spinner.fail('Failed to update all policies');\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Check policy health\n */\n async checkHealth(): Promise<void> {\n const spinner = ora('Checking policy health...').start();\n\n try {\n const { data, error } = await this.supabase\n .rpc('check_rbac_policy_health');\n\n if (error) throw error;\n\n spinner.succeed('Policy health check complete');\n\n if (data.length === 0) {\n console.log(chalk.yellow('No policies found.'));\n return;\n }\n\n const healthyPolicies = data.filter((h: HealthCheck) => h.is_healthy);\n const unhealthyPolicies = data.filter((h: HealthCheck) => !h.is_healthy);\n\n console.log(chalk.green(`✓ ${healthyPolicies.length} healthy policies`));\n console.log(chalk.red(`✗ ${unhealthyPolicies.length} unhealthy policies`));\n\n if (unhealthyPolicies.length > 0) {\n console.log('\\n' + chalk.red('Unhealthy Policies:'));\n const table = new Table({\n head: ['Table', 'Policy', 'Operation', 'Issues'],\n colWidths: [20, 25, 10, 40]\n });\n\n unhealthyPolicies.forEach((policy: HealthCheck) => {\n table.push([\n policy.table_name,\n policy.policy_name,\n policy.operation,\n policy.issues.join(', ')\n ]);\n });\n\n console.log(table.toString());\n }\n } catch (error) {\n spinner.fail('Failed to check policy health');\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Show policy audit log\n */\n async showAudit(limit: number = 20): Promise<void> {\n const spinner = ora('Fetching audit log...').start();\n\n try {\n const { data, error } = await this.supabase\n .from('rbac_policy_audit')\n .select('*')\n .order('changed_at', { ascending: false })\n .limit(limit);\n\n if (error) throw error;\n\n spinner.succeed('Fetched audit log');\n\n if (data.length === 0) {\n console.log(chalk.yellow('No audit entries found.'));\n return;\n }\n\n const table = new Table({\n head: ['Table', 'Policy', 'Operation', 'Action', 'Success', 'Changed At'],\n colWidths: [15, 20, 10, 10, 8, 20]\n });\n\n data.forEach((audit: PolicyAudit) => {\n table.push([\n audit.table_name,\n audit.policy_name,\n audit.operation,\n audit.action,\n audit.success ? chalk.green('✓') : chalk.red('✗'),\n new Date(audit.changed_at).toLocaleString()\n ]);\n });\n\n console.log(table.toString());\n } catch (error) {\n spinner.fail('Failed to fetch audit log');\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n\n /**\n * Test permission check\n */\n async testPermission(\n operation: string,\n pageName: string,\n orgId: string,\n eventId?: string,\n appName: string = 'CAKE'\n ): Promise<void> {\n const spinner = ora('Testing permission check...').start();\n\n try {\n const { data, error } = await this.supabase\n .rpc('check_rbac_permission_with_context', {\n p_operation: operation,\n p_page_name: pageName,\n p_resource_organisation_id: orgId,\n p_resource_event_id: eventId,\n p_app_name: appName\n });\n\n if (error) throw error;\n\n spinner.succeed('Permission check complete');\n\n const result = data ? chalk.green('ALLOWED') : chalk.red('DENIED');\n console.log(`Permission: ${operation} on ${pageName} = ${result}`);\n } catch (error) {\n spinner.fail('Failed to test permission');\n console.error(chalk.red('Error:'), error instanceof Error ? error.message : String(error));\n }\n }\n}\n\n// CLI Setup\nconst program = new Command();\n\nprogram\n .name('rbac-policy-manager')\n .description('CLI tool for managing RBAC-RLS integration policies')\n .version('1.0.0');\n\n// Global options\nprogram\n .option('-u, --url <url>', 'Supabase URL', process.env.SUPABASE_URL)\n .option('-k, --key <key>', 'Supabase service key', process.env.SUPABASE_SERVICE_ROLE_KEY)\n .option('--verbose', 'Enable verbose output');\n\n// List tables command\nprogram\n .command('list')\n .description('List all registered tables')\n .action(async (options) => {\n const url = options.parent?.url || process.env.SUPABASE_URL;\n const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.listTables();\n });\n\n// Register table command\nprogram\n .command('register <tableName> <pageName>')\n .description('Register a table for RBAC policy management')\n .option('-a, --app <appName>', 'App name', 'CAKE')\n .option('-o, --org-column <column>', 'Organisation column name', 'organisation_id')\n .option('-e, --event-column <column>', 'Event column name')\n .option('--operations <operations>', 'Comma-separated operations', 'read,create,update,delete')\n .action(async (tableName, pageName, options) => {\n const operations = options.operations.split(',').map((op: string) => op.trim());\n const url = options.parent?.url || process.env.SUPABASE_URL;\n const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.registerTable(\n tableName,\n pageName,\n options.app,\n options.orgColumn,\n options.eventColumn,\n operations\n );\n });\n\n// Update table command\nprogram\n .command('update <tableName> <pageName>')\n .description('Update policies for a specific table')\n .option('-a, --app <appName>', 'App name', 'CAKE')\n .action(async (tableName, pageName, options) => {\n const url = options.parent?.url || process.env.SUPABASE_URL;\n const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.updateTable(tableName, pageName, options.app);\n });\n\n// Update all command\nprogram\n .command('update-all')\n .description('Update all RBAC policies')\n .action(async (options) => {\n const url = options.url || process.env.SUPABASE_URL;\n const key = options.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.updateAll();\n });\n\n// Health check command\nprogram\n .command('health')\n .description('Check policy health')\n .action(async (options) => {\n const url = options.url || process.env.SUPABASE_URL;\n const key = options.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.checkHealth();\n });\n\n// Audit command\nprogram\n .command('audit')\n .description('Show policy audit log')\n .option('-l, --limit <number>', 'Number of entries to show', '20')\n .action(async (options) => {\n const url = options.parent?.url || process.env.SUPABASE_URL;\n const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.showAudit(parseInt(options.limit));\n });\n\n// Test permission command\nprogram\n .command('test <operation> <pageName> <orgId>')\n .description('Test a permission check')\n .option('-e, --event-id <eventId>', 'Event ID')\n .option('-a, --app <appName>', 'App name', 'CAKE')\n .action(async (operation, pageName, orgId, options) => {\n const url = options.parent?.url || process.env.SUPABASE_URL;\n const key = options.parent?.key || process.env.SUPABASE_SERVICE_ROLE_KEY;\n const manager = new PolicyManager(url, key);\n await manager.testPermission(operation, pageName, orgId, options.eventId, options.app);\n });\n\n// Parse command line arguments\nprogram.parse(process.argv);\n\n// Handle missing required options\nif (!process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_ROLE_KEY) {\n console.error(chalk.red('Error: Missing required environment variables'));\n console.error('Please set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\n process.exit(1);\n}\n\nexport { PolicyManager };\n"],"mappings":"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","names":[]}
@@ -1,96 +0,0 @@
1
- [@jmruthers/pace-core - v0.5.74](../README.md) / [Exports](../modules.md) / EventContextType
2
-
3
- # Interface: EventContextType
4
-
5
- ## Table of contents
6
-
7
- ### Properties
8
-
9
- - [events](EventContextType.md#events)
10
- - [selectedEvent](EventContextType.md#selectedevent)
11
- - [isLoading](EventContextType.md#isloading)
12
- - [error](EventContextType.md#error)
13
- - [setSelectedEvent](EventContextType.md#setselectedevent)
14
- - [refreshEvents](EventContextType.md#refreshevents)
15
-
16
- ## Properties
17
-
18
- ### events
19
-
20
- • **events**: `Event`[]
21
-
22
- #### Defined in
23
-
24
- [packages/core/src/providers/EventProvider.tsx:21](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L21)
25
-
26
- ___
27
-
28
- ### selectedEvent
29
-
30
- • **selectedEvent**: ``null`` \| `Event`
31
-
32
- #### Defined in
33
-
34
- [packages/core/src/providers/EventProvider.tsx:22](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L22)
35
-
36
- ___
37
-
38
- ### isLoading
39
-
40
- • **isLoading**: `boolean`
41
-
42
- #### Defined in
43
-
44
- [packages/core/src/providers/EventProvider.tsx:23](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L23)
45
-
46
- ___
47
-
48
- ### error
49
-
50
- • **error**: ``null`` \| `Error`
51
-
52
- #### Defined in
53
-
54
- [packages/core/src/providers/EventProvider.tsx:24](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L24)
55
-
56
- ___
57
-
58
- ### setSelectedEvent
59
-
60
- • **setSelectedEvent**: (`event`: ``null`` \| `Event`) => `void`
61
-
62
- #### Type declaration
63
-
64
- ▸ (`event`): `void`
65
-
66
- ##### Parameters
67
-
68
- | Name | Type |
69
- | :------ | :------ |
70
- | `event` | ``null`` \| `Event` |
71
-
72
- ##### Returns
73
-
74
- `void`
75
-
76
- #### Defined in
77
-
78
- [packages/core/src/providers/EventProvider.tsx:25](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L25)
79
-
80
- ___
81
-
82
- ### refreshEvents
83
-
84
- • **refreshEvents**: () => `Promise`\<`void`\>
85
-
86
- #### Type declaration
87
-
88
- ▸ (): `Promise`\<`void`\>
89
-
90
- ##### Returns
91
-
92
- `Promise`\<`void`\>
93
-
94
- #### Defined in
95
-
96
- [packages/core/src/providers/EventProvider.tsx:26](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L26)
@@ -1,19 +0,0 @@
1
- [@jmruthers/pace-core - v0.5.74](../README.md) / [Exports](../modules.md) / EventProviderProps
2
-
3
- # Interface: EventProviderProps
4
-
5
- ## Table of contents
6
-
7
- ### Properties
8
-
9
- - [children](EventProviderProps.md#children)
10
-
11
- ## Properties
12
-
13
- ### children
14
-
15
- • **children**: `ReactNode`
16
-
17
- #### Defined in
18
-
19
- [packages/core/src/providers/EventProvider.tsx:40](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/providers/EventProvider.tsx#L40)
@@ -1,164 +0,0 @@
1
- /**
2
- * @file Organisation Provider Tests (Simplified)
3
- * @package @jmruthers/pace-core
4
- * @module Providers/OrganisationProvider
5
- * @since 0.5.0
6
- *
7
- * Simplified tests that mock the OrganisationProvider context directly
8
- * rather than testing the full provider implementation.
9
- */
10
-
11
- import React from 'react';
12
- import { render, screen } from '@testing-library/react';
13
- import { vi, describe, it, expect, beforeEach } from 'vitest';
14
- import type { OrganisationContextType, Organisation } from '../types/organisation';
15
-
16
- // Create a simple mock context
17
- const createMockOrganisationContext = (overrides?: Partial<OrganisationContextType>): OrganisationContextType => {
18
- const mockOrg: Organisation = {
19
- id: 'org-123',
20
- name: 'test-org',
21
- display_name: 'Test Organisation',
22
- subscription_tier: 'standard',
23
- settings: {},
24
- is_active: true,
25
- created_at: '2023-01-01T00:00:00Z',
26
- updated_at: '2023-01-01T00:00:00Z'
27
- };
28
-
29
- return {
30
- selectedOrganisation: mockOrg,
31
- organisations: [mockOrg],
32
- userMemberships: [],
33
- isLoading: false,
34
- error: null,
35
- hasValidOrganisationContext: true,
36
- setSelectedOrganisation: vi.fn(),
37
- switchOrganisation: vi.fn().mockResolvedValue(undefined),
38
- getUserRole: vi.fn().mockReturnValue('org_admin'),
39
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
40
- refreshOrganisations: vi.fn().mockResolvedValue(undefined),
41
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrg),
42
- isOrganisationSecure: vi.fn().mockReturnValue(true),
43
- getPrimaryOrganisation: vi.fn().mockReturnValue(mockOrg),
44
- ...overrides
45
- };
46
- };
47
-
48
- // Mock the useOrganisations hook
49
- vi.mock('./OrganisationProvider', async () => {
50
- const actual = await vi.importActual('./OrganisationProvider');
51
- return {
52
- ...actual,
53
- useOrganisations: vi.fn()
54
- };
55
- });
56
-
57
- import { useOrganisations } from './OrganisationProvider';
58
-
59
- describe('OrganisationProvider Context', () => {
60
- const mockUseOrganisations = vi.mocked(useOrganisations);
61
-
62
- it('provides organisation context to consumers', () => {
63
- const mockContext = createMockOrganisationContext();
64
- mockUseOrganisations.mockReturnValue(mockContext);
65
-
66
- const TestComponent = () => {
67
- const context = useOrganisations();
68
- return (
69
- <div>
70
- <div data-testid="org-id">{context.selectedOrganisation.id}</div>
71
- <div data-testid="org-name">{context.selectedOrganisation.display_name}</div>
72
- <div data-testid="has-context">{context.hasValidOrganisationContext.toString()}</div>
73
- </div>
74
- );
75
- };
76
-
77
- render(<TestComponent />);
78
-
79
- expect(screen.getByTestId('org-id')).toHaveTextContent('org-123');
80
- expect(screen.getByTestId('org-name')).toHaveTextContent('Test Organisation');
81
- expect(screen.getByTestId('has-context')).toHaveTextContent('true');
82
- });
83
-
84
- it('provides organisation methods', () => {
85
- const mockSwitchOrganisation = vi.fn().mockResolvedValue(undefined);
86
- const mockGetUserRole = vi.fn().mockReturnValue('org_admin');
87
-
88
- const mockContext = createMockOrganisationContext({
89
- switchOrganisation: mockSwitchOrganisation,
90
- getUserRole: mockGetUserRole
91
- });
92
- mockUseOrganisations.mockReturnValue(mockContext);
93
-
94
- const TestComponent = () => {
95
- const context = useOrganisations();
96
- return (
97
- <div>
98
- <div data-testid="user-role">{context.getUserRole()}</div>
99
- <button onClick={() => context.switchOrganisation('org-456')}>Switch</button>
100
- </div>
101
- );
102
- };
103
-
104
- render(<TestComponent />);
105
-
106
- expect(screen.getByTestId('user-role')).toHaveTextContent('org_admin');
107
- expect(mockGetUserRole).toHaveBeenCalled();
108
- });
109
-
110
- it('handles loading state', () => {
111
- const mockContext = createMockOrganisationContext({
112
- isLoading: true,
113
- selectedOrganisation: {
114
- id: '',
115
- name: '',
116
- display_name: '',
117
- subscription_tier: 'standard',
118
- settings: {},
119
- is_active: false,
120
- created_at: '',
121
- updated_at: ''
122
- }
123
- });
124
- mockUseOrganisations.mockReturnValue(mockContext);
125
-
126
- const TestComponent = () => {
127
- const context = useOrganisations();
128
- return (
129
- <div>
130
- <div data-testid="loading">{context.isLoading.toString()}</div>
131
- </div>
132
- );
133
- };
134
-
135
- render(<TestComponent />);
136
-
137
- expect(screen.getByTestId('loading')).toHaveTextContent('true');
138
- });
139
-
140
- it('handles error state', () => {
141
- const mockError = new Error('Failed to load organisations');
142
- const mockContext = createMockOrganisationContext({
143
- error: mockError,
144
- hasValidOrganisationContext: false
145
- });
146
- mockUseOrganisations.mockReturnValue(mockContext);
147
-
148
- const TestComponent = () => {
149
- const context = useOrganisations();
150
- return (
151
- <div>
152
- <div data-testid="error">{context.error?.message || 'No error'}</div>
153
- <div data-testid="has-context">{context.hasValidOrganisationContext.toString()}</div>
154
- </div>
155
- );
156
- };
157
-
158
- render(<TestComponent />);
159
-
160
- expect(screen.getByTestId('error')).toHaveTextContent('Failed to load organisations');
161
- expect(screen.getByTestId('has-context')).toHaveTextContent('false');
162
- });
163
- });
164
-