@jmruthers/pace-core 0.5.68 → 0.5.70

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 (394) hide show
  1. package/dist/{DataTable-4IUY7BXB.js → DataTable-OSELOGMA.js} +6 -6
  2. package/dist/{PublicLoadingSpinner-DdKXTkCZ.d.ts → PublicLoadingSpinner-DLpF5bbs.d.ts} +78 -2
  3. package/dist/{chunk-OPCWH3A4.js → chunk-4YMVZ76F.js} +7 -6
  4. package/dist/chunk-4YMVZ76F.js.map +1 -0
  5. package/dist/{chunk-NN45OBIS.js → chunk-5G7JA3L5.js} +3 -5
  6. package/dist/{chunk-NN45OBIS.js.map → chunk-5G7JA3L5.js.map} +1 -1
  7. package/dist/{chunk-U6GPOF6J.js → chunk-5NV76BYF.js} +666 -110
  8. package/dist/chunk-5NV76BYF.js.map +1 -0
  9. package/dist/{chunk-D7ARGIA3.js → chunk-6RBH67W7.js} +23 -6
  10. package/dist/chunk-6RBH67W7.js.map +1 -0
  11. package/dist/{chunk-ZPG4XPV5.js → chunk-BHBMXMLT.js} +5 -7
  12. package/dist/chunk-BHBMXMLT.js.map +1 -0
  13. package/dist/{chunk-ZMS23NS5.js → chunk-FOT3WUV6.js} +3 -5
  14. package/dist/{chunk-ZMS23NS5.js.map → chunk-FOT3WUV6.js.map} +1 -1
  15. package/dist/{chunk-MOJXHWDE.js → chunk-GCUIIBLB.js} +382 -5
  16. package/dist/chunk-GCUIIBLB.js.map +1 -0
  17. package/dist/{chunk-PXWEDX7Y.js → chunk-KWQH4VO3.js} +3 -3
  18. package/dist/{chunk-ZPK5656W.js → chunk-O3NWNXDY.js} +4 -5
  19. package/dist/chunk-O3NWNXDY.js.map +1 -0
  20. package/dist/{chunk-KRCRNXPD.js → chunk-OTJUAYBG.js} +81 -18
  21. package/dist/chunk-OTJUAYBG.js.map +1 -0
  22. package/dist/chunk-SMJZMKYN.js +141 -0
  23. package/dist/chunk-SMJZMKYN.js.map +1 -0
  24. package/dist/{chunk-UYA6U6H7.js → chunk-V2TE7LOF.js} +4 -4
  25. package/dist/{chunk-L3RV2ALE.js → chunk-VKOCWWVY.js} +6 -1
  26. package/dist/{chunk-L3RV2ALE.js.map → chunk-VKOCWWVY.js.map} +1 -1
  27. package/dist/components.d.ts +4 -79
  28. package/dist/components.js +23 -581
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.d.ts +1 -1
  31. package/dist/hooks.js +9 -6
  32. package/dist/hooks.js.map +1 -1
  33. package/dist/index.d.ts +4 -3
  34. package/dist/index.js +32 -19
  35. package/dist/index.js.map +1 -1
  36. package/dist/providers.js +6 -7
  37. package/dist/rbac/index.js +6 -6
  38. package/dist/styles/index.js +2 -2
  39. package/dist/theming/runtime.d.ts +4 -3
  40. package/dist/theming/runtime.js +3 -1
  41. package/dist/{usePublicRouteParams-CdoFxnJK.d.ts → usePublicRouteParams-Ua1Vz-HG.d.ts} +35 -1
  42. package/dist/utils.d.ts +4 -1
  43. package/dist/utils.js +3 -3
  44. package/docs/DOCUMENTATION_CHECKLIST.md +281 -0
  45. package/docs/README.md +22 -10
  46. package/docs/api/classes/ColumnFactory.md +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +1 -1
  49. package/docs/api/classes/MissingUserContextError.md +1 -1
  50. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  51. package/docs/api/classes/PermissionDeniedError.md +1 -1
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +1 -1
  54. package/docs/api/classes/RBACCache.md +1 -1
  55. package/docs/api/classes/RBACEngine.md +1 -1
  56. package/docs/api/classes/RBACError.md +1 -1
  57. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  58. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  59. package/docs/api/classes/StorageUtils.md +1 -1
  60. package/docs/api/enums/FileCategory.md +129 -0
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/ButtonProps.md +1 -1
  63. package/docs/api/interfaces/CardProps.md +1 -1
  64. package/docs/api/interfaces/ColorPalette.md +1 -1
  65. package/docs/api/interfaces/ColorShade.md +1 -1
  66. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  67. package/docs/api/interfaces/DataTableAction.md +1 -1
  68. package/docs/api/interfaces/DataTableColumn.md +1 -1
  69. package/docs/api/interfaces/DataTableProps.md +1 -1
  70. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  71. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  72. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  73. package/docs/api/interfaces/EventContextType.md +7 -7
  74. package/docs/api/interfaces/EventLogoProps.md +1 -1
  75. package/docs/api/interfaces/EventProviderProps.md +2 -2
  76. package/docs/api/interfaces/FileDisplayProps.md +107 -0
  77. package/docs/api/interfaces/FileMetadata.md +129 -0
  78. package/docs/api/interfaces/FileReference.md +118 -0
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +85 -0
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  84. package/docs/api/interfaces/InputProps.md +1 -1
  85. package/docs/api/interfaces/LabelProps.md +1 -1
  86. package/docs/api/interfaces/LoginFormProps.md +1 -1
  87. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  88. package/docs/api/interfaces/NavigationContextType.md +1 -1
  89. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  90. package/docs/api/interfaces/NavigationItem.md +1 -1
  91. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  92. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  93. package/docs/api/interfaces/Organisation.md +1 -1
  94. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  95. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  96. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  97. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  98. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  99. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  100. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  101. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  102. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  103. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  104. package/docs/api/interfaces/PaletteData.md +1 -1
  105. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  106. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  107. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  108. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  109. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  110. package/docs/api/interfaces/PublicPageHeaderProps.md +2 -2
  111. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  112. package/docs/api/interfaces/RBACConfig.md +1 -1
  113. package/docs/api/interfaces/RBACContextType.md +1 -1
  114. package/docs/api/interfaces/RBACLogger.md +1 -1
  115. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  116. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  118. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  119. package/docs/api/interfaces/RouteConfig.md +1 -1
  120. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  121. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  122. package/docs/api/interfaces/StorageConfig.md +1 -1
  123. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  124. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  125. package/docs/api/interfaces/StorageListOptions.md +1 -1
  126. package/docs/api/interfaces/StorageListResult.md +1 -1
  127. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  128. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  129. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  130. package/docs/api/interfaces/StyleImport.md +1 -1
  131. package/docs/api/interfaces/SwitchProps.md +1 -1
  132. package/docs/api/interfaces/ToastActionElement.md +1 -1
  133. package/docs/api/interfaces/ToastProps.md +1 -1
  134. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  135. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  136. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  137. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  138. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  139. package/docs/api/interfaces/UsePublicEventLogoReturn.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/UsePublicRouteParamsReturn.md +1 -1
  143. package/docs/api/interfaces/UserEventAccess.md +1 -1
  144. package/docs/api/interfaces/UserMenuProps.md +1 -1
  145. package/docs/api/interfaces/UserProfile.md +1 -1
  146. package/docs/api/modules.md +228 -23
  147. package/docs/architecture/services.md +374 -0
  148. package/docs/best-practices/README.md +1 -1
  149. package/docs/best-practices/testing.md +1 -1
  150. package/docs/breaking-changes.md +182 -0
  151. package/docs/common-patterns.md +445 -0
  152. package/docs/core-concepts/authentication.md +26 -11
  153. package/docs/core-concepts/events.md +2 -0
  154. package/docs/core-concepts/organisations.md +2 -0
  155. package/docs/core-concepts/permissions.md +2 -0
  156. package/docs/{INDEX.md → documentation-index.md} +26 -38
  157. package/docs/faq.md +286 -0
  158. package/docs/{FILE_REFERENCE_SYSTEM.md → file-reference-system.md} +1 -1
  159. package/docs/getting-started/installation-guide.md +284 -0
  160. package/docs/getting-started/quick-start.md +8 -1
  161. package/docs/implementation-guides/app-layout.md +3 -1
  162. package/docs/implementation-guides/data-tables.md +2 -0
  163. package/docs/implementation-guides/dynamic-colors.md +47 -2
  164. package/docs/implementation-guides/event-theming-summary.md +220 -0
  165. package/docs/implementation-guides/forms.md +9 -7
  166. package/docs/implementation-guides/navigation.md +2 -0
  167. package/docs/migration/service-architecture.md +351 -0
  168. package/docs/rbac/README-rbac-rls-integration.md +2 -2
  169. package/docs/rbac/README.md +1 -1
  170. package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
  171. package/docs/rbac/quick-start.md +2 -0
  172. package/docs/rbac/rbac-rls-integration.md +2 -2
  173. package/docs/style-guide.md +136 -1
  174. package/docs/testing/README.md +1 -1
  175. package/docs/troubleshooting/authentication-issues.md +334 -0
  176. package/docs/troubleshooting/common-issues.md +2 -0
  177. package/docs/troubleshooting/styling-issues.md +199 -144
  178. package/docs/usage.md +23 -2
  179. package/package.json +3 -2
  180. package/src/__tests__/{TESTING_GUIDELINES.md → TEST_GUIDE_CURSOR.md} +20 -0
  181. package/src/__tests__/TEST_GUIDE_HUMAN.md +103 -0
  182. package/src/__tests__/fixtures/test-data.ts +90 -0
  183. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +260 -0
  184. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +224 -0
  185. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +273 -0
  186. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +98 -0
  187. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +436 -0
  188. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +371 -0
  189. package/src/__tests__/helpers/component-test-utils.tsx +14 -4
  190. package/src/__tests__/helpers/optimized-test-setup.ts +68 -0
  191. package/src/__tests__/helpers/test-providers.tsx +329 -0
  192. package/src/__tests__/helpers/test-utils.tsx +91 -45
  193. package/src/__tests__/helpers/timer-utils.ts +71 -0
  194. package/src/__tests__/hooks/usePermissions.test.ts +1 -5
  195. package/src/__tests__/integration/UserProfile.test.tsx +1 -5
  196. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +42 -12
  197. package/src/__tests__/setup.ts +34 -28
  198. package/src/components/Alert/Alert.test.tsx +1 -5
  199. package/src/components/Avatar/Avatar.test.tsx +1 -5
  200. package/src/components/Button/Button.test.tsx +4 -20
  201. package/src/components/Card/Card.test.tsx +1 -5
  202. package/src/components/Checkbox/Checkbox.test.tsx +1 -5
  203. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -5
  204. package/src/components/DataTable/__tests__/DataTable.test.tsx +45 -49
  205. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +1 -5
  206. package/src/components/DataTable/__tests__/styles.test.ts +382 -0
  207. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +409 -0
  208. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +634 -0
  209. package/src/components/DataTable/core/__tests__/DataManager.test.ts +519 -0
  210. package/src/components/DataTable/core/__tests__/StateManager.test.ts +714 -0
  211. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +592 -0
  212. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +354 -0
  213. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +539 -0
  214. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +1 -5
  215. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +1 -8
  216. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +34 -38
  217. package/src/components/Footer/Footer.test.tsx +1 -5
  218. package/src/components/Form/Form.test.tsx +22 -35
  219. package/src/components/Header/Header.test.tsx +1 -9
  220. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +1 -5
  221. package/src/components/Input/Input.test.tsx +2 -10
  222. package/src/components/LoginForm/LoginForm.test.tsx +1 -5
  223. package/src/components/NavigationMenu/NavigationMenu.test.tsx +24 -24
  224. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +1 -6
  225. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +6 -16
  226. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +1 -4
  227. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +1 -5
  228. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +1 -7
  229. package/src/components/PasswordReset/PasswordChangeForm.test.tsx +1 -9
  230. package/src/components/PasswordReset/PasswordResetForm.test.tsx +1 -9
  231. package/src/components/PublicLayout/PublicErrorBoundary.tsx +4 -5
  232. package/src/components/PublicLayout/PublicPageHeader.tsx +13 -9
  233. package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +666 -0
  234. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +457 -0
  235. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +393 -0
  236. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +351 -0
  237. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +374 -0
  238. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +388 -0
  239. package/src/components/Select/Select.bug-test.tsx +69 -0
  240. package/src/components/Select/Select.refactored.tsx +497 -0
  241. package/src/components/Select/Select.test.tsx +42 -49
  242. package/src/components/Select/Select.tsx +5 -2
  243. package/src/components/Select/hooks.ts +254 -0
  244. package/src/components/Switch/Switch.test.tsx +1 -5
  245. package/src/components/Table/__tests__/Table.test.tsx +775 -0
  246. package/src/components/Toast/Toast.test.tsx +15 -8
  247. package/src/components/Tooltip/Tooltip.test.tsx +1 -5
  248. package/src/components/UserMenu/UserMenu.test.tsx +3 -15
  249. package/src/components/__tests__/FileDisplay.test.tsx +575 -0
  250. package/src/components/__tests__/FileUpload.test.tsx +446 -0
  251. package/src/components/__tests__/SuperAdminGuard.test.tsx +422 -354
  252. package/src/hooks/__tests__/ServiceHooks.test.tsx +613 -0
  253. package/src/hooks/__tests__/hooks.integration.test.tsx +1 -10
  254. package/src/hooks/__tests__/useApiFetch.unit.test.ts +10 -14
  255. package/src/hooks/__tests__/useAppConfig.unit.test.ts +307 -0
  256. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +1 -6
  257. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +1 -5
  258. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +6 -9
  259. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +321 -0
  260. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  261. package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +640 -0
  262. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +435 -0
  263. package/src/hooks/__tests__/useRBAC.unit.test.ts +10 -10
  264. package/src/hooks/__tests__/useStorage.unit.test.ts +751 -0
  265. package/src/hooks/index.ts +3 -0
  266. package/src/hooks/public/usePublicEvent.ts +30 -9
  267. package/src/hooks/public/usePublicRouteParams.ts +13 -3
  268. package/src/hooks/services/useAuth.ts +50 -0
  269. package/src/hooks/services/useAuthService.ts +30 -0
  270. package/src/hooks/services/useCurrentEvent.ts +36 -0
  271. package/src/hooks/services/useCurrentOrganisation.ts +52 -0
  272. package/src/hooks/services/useEventService.ts +30 -0
  273. package/src/hooks/services/useInactivityService.ts +30 -0
  274. package/src/hooks/services/useOrganisationService.ts +30 -0
  275. package/src/hooks/services/usePermissions.ts +70 -0
  276. package/src/hooks/services/useRBACService.ts +30 -0
  277. package/src/hooks/useCounter.test.ts +1 -5
  278. package/src/hooks/useEventTheme.ts +86 -0
  279. package/src/hooks/useOrganisationPermissions.test.ts +2 -5
  280. package/src/hooks/useOrganisationSecurity.test.ts +1 -5
  281. package/src/hooks/usePermissionCache.test.ts +1 -5
  282. package/src/hooks/usePermissionCheck.ts +150 -0
  283. package/src/hooks/useSecureDataAccess.test.ts +1 -5
  284. package/src/index.ts +7 -0
  285. package/src/providers/EventProvider.tsx +58 -2
  286. package/src/providers/OrganisationProvider.test.tsx +1 -5
  287. package/src/providers/OrganisationProvider.tsx +56 -4
  288. package/src/providers/UnifiedAuthProvider.test.tsx +1 -5
  289. package/src/providers/__tests__/AuthProvider.test.tsx +105 -439
  290. package/src/providers/__tests__/AuthProvider.test.tsx.backup +771 -0
  291. package/src/providers/__tests__/EventProvider.test.tsx +211 -110
  292. package/src/providers/__tests__/EventProvider.test.tsx.backup +824 -0
  293. package/src/providers/__tests__/InactivityProvider.test.tsx +1 -5
  294. package/src/providers/__tests__/OrganisationProvider.test.tsx +97 -261
  295. package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +820 -0
  296. package/src/providers/__tests__/ServiceProviders.test.tsx +477 -0
  297. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +72 -504
  298. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +911 -0
  299. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +166 -0
  300. package/src/providers/services/AuthServiceProvider.tsx +65 -0
  301. package/src/providers/services/EventServiceProvider.tsx +83 -0
  302. package/src/providers/services/InactivityServiceProvider.tsx +83 -0
  303. package/src/providers/services/OrganisationServiceProvider.tsx +77 -0
  304. package/src/providers/services/RBACServiceProvider.tsx +79 -0
  305. package/src/providers/services/UnifiedAuthProvider.tsx +368 -0
  306. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +210 -0
  307. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +269 -0
  308. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +892 -0
  309. package/src/rbac/__tests__/engine.comprehensive.test.ts +954 -0
  310. package/src/rbac/__tests__/integration.authflow.test.tsx +1 -5
  311. package/src/rbac/__tests__/integration.navigation.test.tsx +1 -4
  312. package/src/rbac/__tests__/rbac-core.test.tsx +2 -7
  313. package/src/rbac/__tests__/rbac-functions.test.ts +1 -9
  314. package/src/rbac/__tests__/rbac-integration.test.ts +1 -9
  315. package/src/rbac/api.test.ts +1 -9
  316. package/src/rbac/cache.test.ts +10 -8
  317. package/src/rbac/cli/__tests__/policy-manager.test.ts +339 -0
  318. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -5
  319. package/src/rbac/components/NavigationProvider.test.tsx +1 -5
  320. package/src/rbac/components/PagePermissionProvider.test.tsx +1 -5
  321. package/src/rbac/components/SecureDataProvider.test.tsx +1 -5
  322. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +25 -29
  323. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +27 -30
  324. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +23 -27
  325. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +18 -22
  326. package/src/rbac/config.test.ts +1 -5
  327. package/src/rbac/hooks/useCan.test.ts +262 -9
  328. package/src/rbac/hooks/usePermissions.test.ts +246 -6
  329. package/src/rbac/hooks/useRBAC.simple.test.ts +1 -5
  330. package/src/rbac/hooks/useRBAC.test.ts +472 -198
  331. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +1 -9
  332. package/src/services/AuthService.ts +416 -0
  333. package/src/services/EventService.ts +366 -0
  334. package/src/services/InactivityService.ts +388 -0
  335. package/src/services/OrganisationService.ts +592 -0
  336. package/src/services/RBACService.ts +522 -0
  337. package/src/services/__tests__/AuthService.test.ts +356 -0
  338. package/src/services/__tests__/BaseService.test.ts +314 -0
  339. package/src/services/__tests__/EventService.test.ts +489 -0
  340. package/src/services/__tests__/InactivityService.test.ts +403 -0
  341. package/src/services/__tests__/OrganisationService.test.ts +660 -0
  342. package/src/services/__tests__/RBACService.test.ts +492 -0
  343. package/src/services/base/BaseService.ts +87 -0
  344. package/src/services/interfaces/IAuthService.ts +39 -0
  345. package/src/services/interfaces/IEventService.ts +30 -0
  346. package/src/services/interfaces/IInactivityService.ts +31 -0
  347. package/src/services/interfaces/IOrganisationService.ts +41 -0
  348. package/src/services/interfaces/IRBACService.ts +62 -0
  349. package/src/theming/__tests__/runtime.test.ts +560 -0
  350. package/src/theming/runtime.ts +71 -28
  351. package/src/types/__tests__/file-reference.test.ts +447 -0
  352. package/src/types/__tests__/organisation.test.ts +1133 -0
  353. package/src/types/__tests__/theme.test.ts +830 -0
  354. package/src/types/__tests__/type-validation.test.ts +527 -0
  355. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +1 -5
  356. package/src/utils/__tests__/debugLogger.test.ts +417 -0
  357. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -6
  358. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -5
  359. package/src/utils/__tests__/lazyLoad.unit.test.tsx +35 -35
  360. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -5
  361. package/src/utils/__tests__/performanceBudgets.unit.test.ts +5 -11
  362. package/src/utils/__tests__/secureErrors.unit.test.ts +1 -6
  363. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -5
  364. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -5
  365. package/src/utils/__tests__/sessionTracking.unit.test.ts +1 -5
  366. package/src/utils/appIdResolver.test.ts +6 -10
  367. package/src/utils/appNameResolver.simple.test.ts +142 -0
  368. package/src/utils/appNameResolver.test.ts +31 -458
  369. package/src/utils/appNameResolver.test.ts.backup +494 -0
  370. package/src/utils/debugLogger.ts +26 -5
  371. package/src/utils/formatDate.test.ts +1 -5
  372. package/src/utils/organisationContext.test.ts +1 -5
  373. package/src/utils/performanceBudgets.ts +3 -4
  374. package/src/utils/secureDataAccess.test.ts +1 -5
  375. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -5
  376. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +1 -5
  377. package/dist/chunk-D7ARGIA3.js.map +0 -1
  378. package/dist/chunk-IPCH4YPT.js +0 -315
  379. package/dist/chunk-IPCH4YPT.js.map +0 -1
  380. package/dist/chunk-KRCRNXPD.js.map +0 -1
  381. package/dist/chunk-MOJXHWDE.js.map +0 -1
  382. package/dist/chunk-N2EUGZRW.js +0 -98
  383. package/dist/chunk-N2EUGZRW.js.map +0 -1
  384. package/dist/chunk-OPCWH3A4.js.map +0 -1
  385. package/dist/chunk-U6GPOF6J.js.map +0 -1
  386. package/dist/chunk-ZPG4XPV5.js.map +0 -1
  387. package/dist/chunk-ZPK5656W.js.map +0 -1
  388. package/docs/getting-started/installation.md +0 -269
  389. package/src/__tests__/REBUILD_PLAN.md +0 -223
  390. package/src/styles/base.css +0 -208
  391. package/src/styles/semantic.css +0 -24
  392. /package/dist/{DataTable-4IUY7BXB.js.map → DataTable-OSELOGMA.js.map} +0 -0
  393. /package/dist/{chunk-PXWEDX7Y.js.map → chunk-KWQH4VO3.js.map} +0 -0
  394. /package/dist/{chunk-UYA6U6H7.js.map → chunk-V2TE7LOF.js.map} +0 -0
@@ -56,8 +56,8 @@ function formatOklchCss(color: ColorShade): string {
56
56
  }
57
57
 
58
58
  /**
59
- * Applies a complete palette to the document by replacing all three palette variable sets.
60
- * Writes a single <style id="pace-theme-dynamic"> block into <head>.
59
+ * Applies a complete palette to the document by setting CSS variables on :root.
60
+ * Uses document.documentElement.style.setProperty() for runtime updates.
61
61
  *
62
62
  * @param palette - Complete palette data with main, sec, and acc palettes
63
63
  */
@@ -69,33 +69,70 @@ export function applyPalette(palette: PaletteData): void {
69
69
  return;
70
70
  }
71
71
 
72
- // Remove existing dynamic theme block
73
- clearPalette();
72
+ const root = document.documentElement;
73
+ const main = palette.main || {};
74
+ const sec = palette.sec || {};
75
+ const acc = palette.acc || {};
76
+
77
+ // Apply main palette
78
+ if (main.raw) {
79
+ root.style.setProperty('--color-main-raw', formatOklchCss(main.raw));
80
+ }
81
+ for (let i = 50; i <= 950; i += 50) {
82
+ const shade = i.toString();
83
+ if (main[shade]) {
84
+ root.style.setProperty(`--color-main-${shade}`, formatOklchCss(main[shade]));
85
+ }
86
+ }
87
+
88
+ // Apply sec palette
89
+ if (sec.raw) {
90
+ root.style.setProperty('--color-sec-raw', formatOklchCss(sec.raw));
91
+ }
92
+ for (let i = 50; i <= 950; i += 50) {
93
+ const shade = i.toString();
94
+ if (sec[shade]) {
95
+ root.style.setProperty(`--color-sec-${shade}`, formatOklchCss(sec[shade]));
96
+ }
97
+ }
98
+
99
+ // Apply acc palette
100
+ if (acc.raw) {
101
+ root.style.setProperty('--color-acc-raw', formatOklchCss(acc.raw));
102
+ }
103
+ for (let i = 50; i <= 950; i += 50) {
104
+ const shade = i.toString();
105
+ if (acc[shade]) {
106
+ root.style.setProperty(`--color-acc-${shade}`, formatOklchCss(acc[shade]));
107
+ }
108
+ }
74
109
 
75
- // Create new style block
76
- const style = document.createElement('style');
77
- style.id = 'pace-theme-dynamic';
78
- style.textContent = generateThemeCSS(palette);
79
-
80
- document.head.appendChild(style);
81
110
  }
82
111
 
83
112
  /**
84
- * Removes the dynamic theme block, returning to app-defined CSS values.
113
+ * Clears dynamic theming by removing CSS variables from :root.
114
+ * This allows the browser to fall back to static CSS values.
85
115
  */
86
116
  export function clearPalette(): void {
87
117
  if (typeof document === 'undefined' || document === null) {
88
118
  return;
89
119
  }
90
120
 
91
- const existingStyle = document.getElementById('pace-theme-dynamic');
92
- if (existingStyle) {
93
- existingStyle.remove();
121
+ const root = document.documentElement;
122
+ const prefixes = ['--color-main-', '--color-sec-', '--color-acc-'];
123
+
124
+ // Remove all dynamically set color variables
125
+ for (let i = root.style.length - 1; i >= 0; i--) {
126
+ const propertyName = root.style[i];
127
+ if (prefixes.some(prefix => propertyName.startsWith(prefix))) {
128
+ root.style.removeProperty(propertyName);
129
+ }
94
130
  }
95
131
  }
96
132
 
97
133
  /**
98
- * Generates CSS for the dynamic theme block
134
+ * Generates CSS for SSR rendering (for server-side rendering)
135
+ * Creates a :root rule with all color variables
99
136
  */
100
137
  function generateThemeCSS(palette: PaletteData): string {
101
138
  // Handle null/undefined palette
@@ -107,7 +144,7 @@ function generateThemeCSS(palette: PaletteData): string {
107
144
  const sec = palette.sec || {};
108
145
  const acc = palette.acc || {};
109
146
 
110
- let css = '@theme static {\n';
147
+ let css = ':root {\n';
111
148
 
112
149
  // MAIN palette
113
150
  css += ' /* MAIN */\n';
@@ -115,8 +152,9 @@ function generateThemeCSS(palette: PaletteData): string {
115
152
  css += ` --color-main-raw: ${formatOklchCss(main.raw)};\n`;
116
153
  }
117
154
  for (let i = 50; i <= 950; i += 50) {
118
- if (main[i.toString()]) {
119
- css += ` --color-main-${i}: ${formatOklchCss(main[i.toString()])};\n`;
155
+ const shade = i.toString();
156
+ if (main[shade]) {
157
+ css += ` --color-main-${shade}: ${formatOklchCss(main[shade])};\n`;
120
158
  }
121
159
  }
122
160
 
@@ -126,8 +164,9 @@ function generateThemeCSS(palette: PaletteData): string {
126
164
  css += ` --color-sec-raw: ${formatOklchCss(sec.raw)};\n`;
127
165
  }
128
166
  for (let i = 50; i <= 950; i += 50) {
129
- if (sec[i.toString()]) {
130
- css += ` --color-sec-${i}: ${formatOklchCss(sec[i.toString()])};\n`;
167
+ const shade = i.toString();
168
+ if (sec[shade]) {
169
+ css += ` --color-sec-${shade}: ${formatOklchCss(sec[shade])};\n`;
131
170
  }
132
171
  }
133
172
 
@@ -137,8 +176,9 @@ function generateThemeCSS(palette: PaletteData): string {
137
176
  css += ` --color-acc-raw: ${formatOklchCss(acc.raw)};\n`;
138
177
  }
139
178
  for (let i = 50; i <= 950; i += 50) {
140
- if (acc[i.toString()]) {
141
- css += ` --color-acc-${i}: ${formatOklchCss(acc[i.toString()])};\n`;
179
+ const shade = i.toString();
180
+ if (acc[shade]) {
181
+ css += ` --color-acc-${shade}: ${formatOklchCss(acc[shade])};\n`;
142
182
  }
143
183
  }
144
184
 
@@ -163,7 +203,9 @@ export function isDynamicThemingActive(): boolean {
163
203
  return false;
164
204
  }
165
205
 
166
- return document.getElementById('pace-theme-dynamic') !== null;
206
+ const root = document.documentElement;
207
+ // Check if any color variables are set on :root
208
+ return root.style.getPropertyValue('--color-main-500') !== '';
167
209
  }
168
210
 
169
211
  /**
@@ -175,13 +217,14 @@ export function getCurrentThemeData(): PaletteData | null {
175
217
  return null;
176
218
  }
177
219
 
178
- const style = document.getElementById('pace-theme-dynamic');
179
- if (!style) {
180
- return null;
181
- }
220
+ const root = document.documentElement;
221
+ const main: ColorPalette = {};
222
+ const sec: ColorPalette = {};
223
+ const acc: ColorPalette = {};
182
224
 
225
+ // Extract CSS variables from :root
183
226
  // This is a simplified implementation
184
- // In a real scenario, you might want to parse the CSS to extract values
227
+ // In a real scenario, you might want to parse the actual color values
185
228
  // For now, we'll return null as the theme data isn't easily extractable
186
229
  return null;
187
230
  }
@@ -0,0 +1,447 @@
1
+ /**
2
+ * @file File Reference Type Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Types/__tests__
5
+ * @since 1.0.0
6
+ */
7
+
8
+ import { describe, it, expect } from 'vitest';
9
+ import type {
10
+ FileReference,
11
+ FileUploadOptions,
12
+ FileUploadResult,
13
+ FileValidationError,
14
+ FileMetadata,
15
+ FileStorageConfig,
16
+ FileAccessLevel
17
+ } from '../file-reference';
18
+
19
+ describe('[types] File Reference Types', () => {
20
+ describe('FileReference interface', () => {
21
+ it('validates FileReference type structure', () => {
22
+ const fileRef: FileReference = {
23
+ id: 'test-file-id',
24
+ filename: 'test-file.pdf',
25
+ originalName: 'Test File.pdf',
26
+ mimeType: 'application/pdf',
27
+ size: 1024,
28
+ url: 'https://example.com/files/test-file.pdf',
29
+ uploadedAt: '2024-01-01T00:00:00Z',
30
+ uploadedBy: 'user-123',
31
+ organisationId: 'org-123',
32
+ eventId: 'event-123',
33
+ accessLevel: 'private',
34
+ metadata: {
35
+ description: 'Test file description',
36
+ tags: ['document', 'test']
37
+ }
38
+ };
39
+
40
+ expect(fileRef).toHaveProperty('id');
41
+ expect(fileRef).toHaveProperty('filename');
42
+ expect(fileRef).toHaveProperty('originalName');
43
+ expect(fileRef).toHaveProperty('mimeType');
44
+ expect(fileRef).toHaveProperty('size');
45
+ expect(fileRef).toHaveProperty('url');
46
+ expect(fileRef).toHaveProperty('uploadedAt');
47
+ expect(fileRef).toHaveProperty('uploadedBy');
48
+ expect(fileRef).toHaveProperty('organisationId');
49
+ expect(fileRef).toHaveProperty('eventId');
50
+ expect(fileRef).toHaveProperty('accessLevel');
51
+ expect(fileRef).toHaveProperty('metadata');
52
+
53
+ expect(typeof fileRef.id).toBe('string');
54
+ expect(typeof fileRef.filename).toBe('string');
55
+ expect(typeof fileRef.originalName).toBe('string');
56
+ expect(typeof fileRef.mimeType).toBe('string');
57
+ expect(typeof fileRef.size).toBe('number');
58
+ expect(typeof fileRef.url).toBe('string');
59
+ expect(typeof fileRef.uploadedAt).toBe('string');
60
+ expect(typeof fileRef.uploadedBy).toBe('string');
61
+ expect(typeof fileRef.organisationId).toBe('string');
62
+ expect(typeof fileRef.eventId).toBe('string');
63
+ expect(typeof fileRef.accessLevel).toBe('string');
64
+ expect(typeof fileRef.metadata).toBe('object');
65
+ });
66
+
67
+ it('validates FileReference with minimal required fields', () => {
68
+ const fileRef: FileReference = {
69
+ id: 'test-file-id',
70
+ filename: 'test-file.pdf',
71
+ originalName: 'Test File.pdf',
72
+ mimeType: 'application/pdf',
73
+ size: 1024,
74
+ url: 'https://example.com/files/test-file.pdf',
75
+ uploadedAt: '2024-01-01T00:00:00Z',
76
+ uploadedBy: 'user-123',
77
+ organisationId: 'org-123',
78
+ accessLevel: 'private'
79
+ };
80
+
81
+ expect(fileRef).toHaveProperty('id');
82
+ expect(fileRef).toHaveProperty('filename');
83
+ expect(fileRef.eventId).toBeUndefined();
84
+ expect(fileRef.metadata).toBeUndefined();
85
+ });
86
+ });
87
+
88
+ describe('FileUploadOptions interface', () => {
89
+ it('validates FileUploadOptions type structure', () => {
90
+ const uploadOptions: FileUploadOptions = {
91
+ maxSize: 5 * 1024 * 1024, // 5MB
92
+ allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
93
+ allowedExtensions: ['.jpg', '.jpeg', '.png', '.pdf'],
94
+ generateThumbnail: true,
95
+ compressImage: true,
96
+ quality: 0.8,
97
+ resize: {
98
+ width: 1920,
99
+ height: 1080,
100
+ maintainAspectRatio: true
101
+ },
102
+ metadata: {
103
+ description: 'Uploaded file',
104
+ tags: ['upload']
105
+ },
106
+ accessLevel: 'private',
107
+ organisationId: 'org-123',
108
+ eventId: 'event-123'
109
+ };
110
+
111
+ expect(uploadOptions).toHaveProperty('maxSize');
112
+ expect(uploadOptions).toHaveProperty('allowedTypes');
113
+ expect(uploadOptions).toHaveProperty('allowedExtensions');
114
+ expect(uploadOptions).toHaveProperty('generateThumbnail');
115
+ expect(uploadOptions).toHaveProperty('compressImage');
116
+ expect(uploadOptions).toHaveProperty('quality');
117
+ expect(uploadOptions).toHaveProperty('resize');
118
+ expect(uploadOptions).toHaveProperty('metadata');
119
+ expect(uploadOptions).toHaveProperty('accessLevel');
120
+ expect(uploadOptions).toHaveProperty('organisationId');
121
+ expect(uploadOptions).toHaveProperty('eventId');
122
+
123
+ expect(typeof uploadOptions.maxSize).toBe('number');
124
+ expect(Array.isArray(uploadOptions.allowedTypes)).toBe(true);
125
+ expect(Array.isArray(uploadOptions.allowedExtensions)).toBe(true);
126
+ expect(typeof uploadOptions.generateThumbnail).toBe('boolean');
127
+ expect(typeof uploadOptions.compressImage).toBe('boolean');
128
+ expect(typeof uploadOptions.quality).toBe('number');
129
+ expect(typeof uploadOptions.resize).toBe('object');
130
+ expect(typeof uploadOptions.metadata).toBe('object');
131
+ expect(typeof uploadOptions.accessLevel).toBe('string');
132
+ expect(typeof uploadOptions.organisationId).toBe('string');
133
+ expect(typeof uploadOptions.eventId).toBe('string');
134
+ });
135
+
136
+ it('validates FileUploadOptions with minimal fields', () => {
137
+ const uploadOptions: FileUploadOptions = {
138
+ maxSize: 1024 * 1024, // 1MB
139
+ allowedTypes: ['image/jpeg'],
140
+ accessLevel: 'public'
141
+ };
142
+
143
+ expect(uploadOptions).toHaveProperty('maxSize');
144
+ expect(uploadOptions).toHaveProperty('allowedTypes');
145
+ expect(uploadOptions).toHaveProperty('accessLevel');
146
+ expect(uploadOptions.allowedExtensions).toBeUndefined();
147
+ expect(uploadOptions.generateThumbnail).toBeUndefined();
148
+ expect(uploadOptions.compressImage).toBeUndefined();
149
+ });
150
+ });
151
+
152
+ describe('FileUploadResult interface', () => {
153
+ it('validates FileUploadResult success structure', () => {
154
+ const successResult: FileUploadResult = {
155
+ success: true,
156
+ file: {
157
+ id: 'test-file-id',
158
+ filename: 'test-file.pdf',
159
+ originalName: 'Test File.pdf',
160
+ mimeType: 'application/pdf',
161
+ size: 1024,
162
+ url: 'https://example.com/files/test-file.pdf',
163
+ uploadedAt: '2024-01-01T00:00:00Z',
164
+ uploadedBy: 'user-123',
165
+ organisationId: 'org-123',
166
+ accessLevel: 'private'
167
+ },
168
+ thumbnailUrl: 'https://example.com/thumbnails/test-file.jpg',
169
+ message: 'File uploaded successfully'
170
+ };
171
+
172
+ expect(successResult).toHaveProperty('success');
173
+ expect(successResult).toHaveProperty('file');
174
+ expect(successResult).toHaveProperty('thumbnailUrl');
175
+ expect(successResult).toHaveProperty('message');
176
+ expect(successResult.success).toBe(true);
177
+ expect(typeof successResult.file).toBe('object');
178
+ expect(typeof successResult.thumbnailUrl).toBe('string');
179
+ expect(typeof successResult.message).toBe('string');
180
+ });
181
+
182
+ it('validates FileUploadResult error structure', () => {
183
+ const errorResult: FileUploadResult = {
184
+ success: false,
185
+ error: 'File size exceeds maximum allowed size',
186
+ code: 'FILE_TOO_LARGE',
187
+ details: {
188
+ maxSize: 5 * 1024 * 1024,
189
+ actualSize: 10 * 1024 * 1024
190
+ }
191
+ };
192
+
193
+ expect(errorResult).toHaveProperty('success');
194
+ expect(errorResult).toHaveProperty('error');
195
+ expect(errorResult).toHaveProperty('code');
196
+ expect(errorResult).toHaveProperty('details');
197
+ expect(errorResult.success).toBe(false);
198
+ expect(typeof errorResult.error).toBe('string');
199
+ expect(typeof errorResult.code).toBe('string');
200
+ expect(typeof errorResult.details).toBe('object');
201
+ expect(errorResult.file).toBeUndefined();
202
+ });
203
+ });
204
+
205
+ describe('FileValidationError interface', () => {
206
+ it('validates FileValidationError type structure', () => {
207
+ const validationError: FileValidationError = {
208
+ field: 'file',
209
+ message: 'File type not allowed',
210
+ code: 'INVALID_FILE_TYPE',
211
+ value: 'test.exe',
212
+ allowedValues: ['image/jpeg', 'image/png', 'application/pdf']
213
+ };
214
+
215
+ expect(validationError).toHaveProperty('field');
216
+ expect(validationError).toHaveProperty('message');
217
+ expect(validationError).toHaveProperty('code');
218
+ expect(validationError).toHaveProperty('value');
219
+ expect(validationError).toHaveProperty('allowedValues');
220
+ expect(typeof validationError.field).toBe('string');
221
+ expect(typeof validationError.message).toBe('string');
222
+ expect(typeof validationError.code).toBe('string');
223
+ expect(typeof validationError.value).toBe('string');
224
+ expect(Array.isArray(validationError.allowedValues)).toBe(true);
225
+ });
226
+ });
227
+
228
+ describe('FileMetadata interface', () => {
229
+ it('validates FileMetadata type structure', () => {
230
+ const metadata: FileMetadata = {
231
+ description: 'Test file description',
232
+ tags: ['document', 'test', 'important'],
233
+ category: 'documents',
234
+ author: 'John Doe',
235
+ version: '1.0',
236
+ customFields: {
237
+ department: 'IT',
238
+ project: 'Test Project',
239
+ priority: 'high'
240
+ }
241
+ };
242
+
243
+ expect(metadata).toHaveProperty('description');
244
+ expect(metadata).toHaveProperty('tags');
245
+ expect(metadata).toHaveProperty('category');
246
+ expect(metadata).toHaveProperty('author');
247
+ expect(metadata).toHaveProperty('version');
248
+ expect(metadata).toHaveProperty('customFields');
249
+ expect(typeof metadata.description).toBe('string');
250
+ expect(Array.isArray(metadata.tags)).toBe(true);
251
+ expect(typeof metadata.category).toBe('string');
252
+ expect(typeof metadata.author).toBe('string');
253
+ expect(typeof metadata.version).toBe('string');
254
+ expect(typeof metadata.customFields).toBe('object');
255
+ });
256
+
257
+ it('validates FileMetadata with minimal fields', () => {
258
+ const metadata: FileMetadata = {
259
+ description: 'Test file'
260
+ };
261
+
262
+ expect(metadata).toHaveProperty('description');
263
+ expect(metadata.tags).toBeUndefined();
264
+ expect(metadata.category).toBeUndefined();
265
+ expect(metadata.author).toBeUndefined();
266
+ expect(metadata.version).toBeUndefined();
267
+ expect(metadata.customFields).toBeUndefined();
268
+ });
269
+ });
270
+
271
+ describe('FileStorageConfig interface', () => {
272
+ it('validates FileStorageConfig type structure', () => {
273
+ const storageConfig: FileStorageConfig = {
274
+ provider: 'supabase',
275
+ bucket: 'pace-files',
276
+ region: 'us-east-1',
277
+ cdnUrl: 'https://cdn.example.com',
278
+ maxFileSize: 10 * 1024 * 1024, // 10MB
279
+ allowedMimeTypes: ['image/*', 'application/pdf', 'text/*'],
280
+ compressionEnabled: true,
281
+ encryptionEnabled: true,
282
+ retentionPolicy: {
283
+ days: 365,
284
+ autoDelete: true
285
+ }
286
+ };
287
+
288
+ expect(storageConfig).toHaveProperty('provider');
289
+ expect(storageConfig).toHaveProperty('bucket');
290
+ expect(storageConfig).toHaveProperty('region');
291
+ expect(storageConfig).toHaveProperty('cdnUrl');
292
+ expect(storageConfig).toHaveProperty('maxFileSize');
293
+ expect(storageConfig).toHaveProperty('allowedMimeTypes');
294
+ expect(storageConfig).toHaveProperty('compressionEnabled');
295
+ expect(storageConfig).toHaveProperty('encryptionEnabled');
296
+ expect(storageConfig).toHaveProperty('retentionPolicy');
297
+ expect(typeof storageConfig.provider).toBe('string');
298
+ expect(typeof storageConfig.bucket).toBe('string');
299
+ expect(typeof storageConfig.region).toBe('string');
300
+ expect(typeof storageConfig.cdnUrl).toBe('string');
301
+ expect(typeof storageConfig.maxFileSize).toBe('number');
302
+ expect(Array.isArray(storageConfig.allowedMimeTypes)).toBe(true);
303
+ expect(typeof storageConfig.compressionEnabled).toBe('boolean');
304
+ expect(typeof storageConfig.encryptionEnabled).toBe('boolean');
305
+ expect(typeof storageConfig.retentionPolicy).toBe('object');
306
+ });
307
+ });
308
+
309
+ describe('FileAccessLevel type', () => {
310
+ it('validates FileAccessLevel values', () => {
311
+ const accessLevels: FileAccessLevel[] = ['public', 'private', 'restricted'];
312
+
313
+ expect(accessLevels).toContain('public');
314
+ expect(accessLevels).toContain('private');
315
+ expect(accessLevels).toContain('restricted');
316
+ });
317
+
318
+ it('validates FileAccessLevel type usage', () => {
319
+ const accessLevel: FileAccessLevel = 'private';
320
+ expect(typeof accessLevel).toBe('string');
321
+ expect(['public', 'private', 'restricted']).toContain(accessLevel);
322
+ });
323
+ });
324
+ });
325
+
326
+ describe('[types] File Reference Usage Patterns', () => {
327
+ describe('File Upload Flow', () => {
328
+ it('validates complete file upload flow types', () => {
329
+ interface FileUploadFlow {
330
+ file: File;
331
+ options: FileUploadOptions;
332
+ onProgress: (progress: number) => void;
333
+ onSuccess: (result: FileUploadResult) => void;
334
+ onError: (error: FileValidationError) => void;
335
+ }
336
+
337
+ const uploadFlow: FileUploadFlow = {
338
+ file: new File(['test'], 'test.txt', { type: 'text/plain' }),
339
+ options: {
340
+ maxSize: 1024 * 1024,
341
+ allowedTypes: ['text/plain'],
342
+ accessLevel: 'private'
343
+ },
344
+ onProgress: (progress) => {
345
+ expect(typeof progress).toBe('number');
346
+ expect(progress).toBeGreaterThanOrEqual(0);
347
+ expect(progress).toBeLessThanOrEqual(100);
348
+ },
349
+ onSuccess: (result) => {
350
+ expect(result).toHaveProperty('success');
351
+ expect(result).toHaveProperty('file');
352
+ },
353
+ onError: (error) => {
354
+ expect(error).toHaveProperty('field');
355
+ expect(error).toHaveProperty('message');
356
+ expect(error).toHaveProperty('code');
357
+ }
358
+ };
359
+
360
+ expect(uploadFlow).toHaveProperty('file');
361
+ expect(uploadFlow).toHaveProperty('options');
362
+ expect(uploadFlow).toHaveProperty('onProgress');
363
+ expect(uploadFlow).toHaveProperty('onSuccess');
364
+ expect(uploadFlow).toHaveProperty('onError');
365
+ expect(uploadFlow.file).toBeInstanceOf(File);
366
+ expect(typeof uploadFlow.options).toBe('object');
367
+ expect(typeof uploadFlow.onProgress).toBe('function');
368
+ expect(typeof uploadFlow.onSuccess).toBe('function');
369
+ expect(typeof uploadFlow.onError).toBe('function');
370
+ });
371
+ });
372
+
373
+ describe('File Management Operations', () => {
374
+ it('validates file management operation types', () => {
375
+ interface FileManagementOperation {
376
+ operation: 'upload' | 'download' | 'delete' | 'update' | 'list';
377
+ fileId?: string;
378
+ options?: FileUploadOptions;
379
+ metadata?: FileMetadata;
380
+ }
381
+
382
+ const operations: FileManagementOperation[] = [
383
+ { operation: 'upload', options: { maxSize: 1024, allowedTypes: ['image/*'] } },
384
+ { operation: 'download', fileId: 'file-123' },
385
+ { operation: 'delete', fileId: 'file-123' },
386
+ { operation: 'update', fileId: 'file-123', metadata: { description: 'Updated' } },
387
+ { operation: 'list' }
388
+ ];
389
+
390
+ operations.forEach(op => {
391
+ expect(op).toHaveProperty('operation');
392
+ expect(['upload', 'download', 'delete', 'update', 'list']).toContain(op.operation);
393
+ if (op.fileId) {
394
+ expect(typeof op.fileId).toBe('string');
395
+ }
396
+ if (op.options) {
397
+ expect(typeof op.options).toBe('object');
398
+ }
399
+ if (op.metadata) {
400
+ expect(typeof op.metadata).toBe('object');
401
+ }
402
+ });
403
+ });
404
+ });
405
+
406
+ describe('File Validation Rules', () => {
407
+ it('validates file validation rule types', () => {
408
+ interface FileValidationRule {
409
+ field: keyof FileReference;
410
+ validator: (value: any) => boolean;
411
+ message: string;
412
+ required?: boolean;
413
+ }
414
+
415
+ const validationRules: FileValidationRule[] = [
416
+ {
417
+ field: 'filename',
418
+ validator: (value) => typeof value === 'string' && value.length > 0,
419
+ message: 'Filename is required',
420
+ required: true
421
+ },
422
+ {
423
+ field: 'size',
424
+ validator: (value) => typeof value === 'number' && value > 0,
425
+ message: 'File size must be greater than 0'
426
+ },
427
+ {
428
+ field: 'mimeType',
429
+ validator: (value) => typeof value === 'string' && value.includes('/'),
430
+ message: 'Invalid MIME type format'
431
+ }
432
+ ];
433
+
434
+ validationRules.forEach(rule => {
435
+ expect(rule).toHaveProperty('field');
436
+ expect(rule).toHaveProperty('validator');
437
+ expect(rule).toHaveProperty('message');
438
+ expect(typeof rule.field).toBe('string');
439
+ expect(typeof rule.validator).toBe('function');
440
+ expect(typeof rule.message).toBe('string');
441
+ if (rule.required !== undefined) {
442
+ expect(typeof rule.required).toBe('boolean');
443
+ }
444
+ });
445
+ });
446
+ });
447
+ });