@jmruthers/pace-core 0.5.193 → 0.6.2

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 (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Build decision logic for documentation generation
5
+ */
6
+
7
+ import { existsSync, statSync } from 'fs';
8
+ import { join } from 'path';
9
+
10
+ /**
11
+ * Aggressive pre-check: Should we run TypeDoc at all?
12
+ * This checks source file hashes BEFORE running TypeDoc to avoid unnecessary runs
13
+ */
14
+ export function shouldRunTypeDoc(config) {
15
+ const {
16
+ cache,
17
+ docsDir,
18
+ repoRoot,
19
+ docsRelevantPaths,
20
+ srcDir,
21
+ shouldSkipDueToCleanGitState,
22
+ primeCacheFromExistingDocs,
23
+ getSourceFileHashes,
24
+ hasSourceChanged,
25
+ getExistingDocHashes,
26
+ hashesMatch
27
+ } = config;
28
+
29
+ // If no cache, must run
30
+ if (cache.lastBuildTime === 0) {
31
+ if (shouldSkipDueToCleanGitState(repoRoot, docsDir, docsRelevantPaths)) {
32
+ console.log('⏭️ Skipping TypeDoc - no cache yet but git shows no relevant source changes.');
33
+ console.log(' Reason: Using checked-in docs since source tree matches HEAD');
34
+ console.log(' Action: Priming docs cache from checked-in files for future runs');
35
+ primeCacheFromExistingDocs({
36
+ cacheFile: config.cacheFile,
37
+ docsDir: config.docsDir,
38
+ srcDir: config.srcDir,
39
+ getLatestSourceModTime: config.getLatestSourceModTime,
40
+ getLatestDocModTime: config.getLatestDocModTime,
41
+ getExistingDocHashes: config.getExistingDocHashes,
42
+ getSourceFileHashes: config.getSourceFileHashes
43
+ });
44
+ return false;
45
+ }
46
+ console.log('📝 No cache found, running TypeDoc...');
47
+ console.log(' Reason: First run - no cache exists');
48
+ return true;
49
+ }
50
+
51
+ // If docs don't exist, must run
52
+ if (!existsSync(docsDir)) {
53
+ console.log('📝 Documentation directory not found, running TypeDoc...');
54
+ console.log(' Reason: Documentation directory missing');
55
+ return true;
56
+ }
57
+
58
+ // Check source file hashes - most reliable check
59
+ console.log('🔍 Checking source file hashes...');
60
+ const currentSourceHashes = getSourceFileHashes(srcDir);
61
+ const cachedSourceHashes = cache.sourceFileHashes || {};
62
+
63
+ console.log(` Current source files: ${currentSourceHashes.size}`);
64
+ console.log(` Cached source files: ${Object.keys(cachedSourceHashes).length}`);
65
+
66
+ if (hasSourceChanged(currentSourceHashes, cachedSourceHashes)) {
67
+ // Find which files changed
68
+ const changedFiles = [];
69
+ for (const [relativePath, currentHash] of currentSourceHashes.entries()) {
70
+ const cachedHash = cachedSourceHashes[relativePath];
71
+ if (cachedHash !== currentHash) {
72
+ changedFiles.push(relativePath);
73
+ }
74
+ }
75
+ console.log('📝 Source files have changed (hash comparison), running TypeDoc...');
76
+ if (changedFiles.length > 0 && changedFiles.length <= 10) {
77
+ console.log(` Changed files: ${changedFiles.slice(0, 5).join(', ')}${changedFiles.length > 5 ? ` ... and ${changedFiles.length - 5} more` : ''}`);
78
+ } else if (changedFiles.length > 10) {
79
+ console.log(` Changed files: ${changedFiles.length} files modified`);
80
+ }
81
+ return true;
82
+ }
83
+
84
+ // Source hasn't changed - check if docs match cache
85
+ console.log('🔍 Checking documentation file hashes...');
86
+ const currentDocHashes = getExistingDocHashes(docsDir);
87
+ const cachedDocHashes = cache.fileHashes || {};
88
+
89
+ console.log(` Current doc files: ${currentDocHashes.size}`);
90
+ console.log(` Cached doc files: ${Object.keys(cachedDocHashes).length}`);
91
+
92
+ if (hashesMatch(currentDocHashes, cachedDocHashes)) {
93
+ console.log('✅ Source unchanged and docs match cache - skipping TypeDoc entirely');
94
+ console.log(' Reason: No source changes detected and documentation is up to date');
95
+ return false; // Skip TypeDoc!
96
+ }
97
+
98
+ // Docs don't match cache but source unchanged - refresh cache snapshot instead of regenerating
99
+ const mismatchedFiles = [];
100
+ for (const [relativePath, currentHash] of currentDocHashes.entries()) {
101
+ const cachedHash = cachedDocHashes[relativePath];
102
+ if (cachedHash !== currentHash) {
103
+ mismatchedFiles.push(relativePath);
104
+ }
105
+ }
106
+ console.log('⚠️ Source unchanged but docs don\'t match cache - refreshing cache from disk');
107
+ console.log(` Mismatched files: ${mismatchedFiles.length} files don't match cache`);
108
+ if (mismatchedFiles.length <= 5) {
109
+ console.log(` Files: ${mismatchedFiles.join(', ')}`);
110
+ }
111
+ primeCacheFromExistingDocs(config);
112
+ return false;
113
+ }
114
+
115
+ /**
116
+ * Check if any source files have changed since last build
117
+ */
118
+ export function needsRebuild(config) {
119
+ const {
120
+ cache,
121
+ packageRoot,
122
+ docsDir,
123
+ srcDir,
124
+ getLatestSourceModTime,
125
+ getLatestDocModTime,
126
+ getExistingDocHashes
127
+ } = config;
128
+
129
+ const ignorePatterns = [
130
+ /\.test\.(ts|tsx)$/,
131
+ /\.spec\.(ts|tsx)$/,
132
+ /__tests__/,
133
+ /\/test\//,
134
+ /\/tests\//
135
+ ];
136
+
137
+ const currentSourceModTime = getLatestSourceModTime(srcDir, ignorePatterns);
138
+ const currentDocModTime = getLatestDocModTime(docsDir);
139
+
140
+ // If docs don't exist, we need to build
141
+ if (!existsSync(docsDir) || currentDocModTime === 0) {
142
+ console.log('📝 Documentation directory not found or empty, building...');
143
+ return true;
144
+ }
145
+
146
+ // Check if typedoc.json has changed
147
+ const typedocConfigPath = join(packageRoot, 'typedoc.json');
148
+ if (existsSync(typedocConfigPath)) {
149
+ const configStats = statSync(typedocConfigPath);
150
+ if (cache.lastBuildTime > 0 && configStats.mtimeMs > cache.lastBuildTime) {
151
+ console.log('📝 TypeDoc configuration has changed, rebuilding...');
152
+ return true;
153
+ }
154
+ if (currentDocModTime > 0 && configStats.mtimeMs > currentDocModTime) {
155
+ console.log('📝 TypeDoc configuration is newer than docs, rebuilding...');
156
+ return true;
157
+ }
158
+ }
159
+
160
+ // Check entry point file (what TypeDoc actually uses)
161
+ const entryPointPath = join(packageRoot, 'src', 'index.ts');
162
+ if (existsSync(entryPointPath)) {
163
+ const entryStats = statSync(entryPointPath);
164
+ if (cache.lastBuildTime > 0 && entryStats.mtimeMs > cache.lastBuildTime) {
165
+ console.log('📝 Entry point file has changed, rebuilding...');
166
+ return true;
167
+ }
168
+ if (currentDocModTime > 0 && entryStats.mtimeMs > currentDocModTime) {
169
+ console.log('📝 Entry point file is newer than docs, rebuilding...');
170
+ return true;
171
+ }
172
+ }
173
+
174
+ // If source files are newer than docs, we need to rebuild
175
+ if (currentSourceModTime > currentDocModTime) {
176
+ console.log('📝 Source files are newer than documentation, rebuilding...');
177
+ return true;
178
+ }
179
+
180
+ // If cache indicates a rebuild is needed (e.g., after a clean)
181
+ // Only check cache if we have a valid cache entry
182
+ if (cache.lastBuildTime > 0) {
183
+ // Check if source files have changed since last build
184
+ const sourceChanged = currentSourceModTime > cache.sourceModTime;
185
+
186
+ // Check if docs are newer than the last build time (meaning they were just built)
187
+ const docsJustBuilt = currentDocModTime > cache.lastBuildTime - 1000; // 1 second tolerance
188
+
189
+ if (sourceChanged) {
190
+ console.log('📝 Source files have changed since last build, rebuilding...');
191
+ return true;
192
+ }
193
+
194
+ // If docs were just built (within last second), skip rebuild to avoid double-building
195
+ if (docsJustBuilt) {
196
+ console.log('✅ Documentation was just built, skipping rebuild to avoid double-build');
197
+ return false;
198
+ }
199
+
200
+ // Check file-level hashes if available
201
+ if (cache.fileHashes && Object.keys(cache.fileHashes).length > 0) {
202
+ const currentHashes = getExistingDocHashes(docsDir);
203
+ let filesChanged = false;
204
+
205
+ // Check if any file hashes changed
206
+ for (const [relativePath, cachedHash] of Object.entries(cache.fileHashes)) {
207
+ const currentHash = currentHashes.get(relativePath);
208
+ if (currentHash !== cachedHash) {
209
+ filesChanged = true;
210
+ break;
211
+ }
212
+ }
213
+
214
+ // Check if any new files were added
215
+ if (!filesChanged && currentHashes.size !== Object.keys(cache.fileHashes).length) {
216
+ filesChanged = true;
217
+ }
218
+
219
+ if (!filesChanged && !sourceChanged) {
220
+ console.log('✅ Documentation is up to date (file hashes match cache), skipping rebuild');
221
+ return false;
222
+ }
223
+ }
224
+
225
+ // If cache exists and source hasn't changed, we're good
226
+ console.log('✅ Documentation is up to date (cache valid), skipping rebuild');
227
+ return false;
228
+ }
229
+
230
+ // No cache exists - compare source vs docs directly
231
+ if (currentSourceModTime <= currentDocModTime) {
232
+ console.log('✅ Documentation is up to date, skipping rebuild');
233
+ return false;
234
+ }
235
+
236
+ // Fallback: rebuild if we can't determine
237
+ console.log('📝 Unable to determine if rebuild needed, rebuilding to be safe...');
238
+ return true;
239
+ }
240
+
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cache utilities for documentation build
5
+ */
6
+
7
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
8
+
9
+ /**
10
+ * Load the cache file
11
+ */
12
+ export function loadCache(cacheFile) {
13
+ if (!existsSync(cacheFile)) {
14
+ return {
15
+ lastBuildTime: 0,
16
+ sourceModTime: 0,
17
+ docModTime: 0,
18
+ fileHashes: {},
19
+ sourceFileHashes: {}
20
+ };
21
+ }
22
+
23
+ try {
24
+ const content = readFileSync(cacheFile, 'utf-8');
25
+ const cache = JSON.parse(content);
26
+ // Ensure fileHashes exists for backward compatibility
27
+ if (!cache.fileHashes) {
28
+ cache.fileHashes = {};
29
+ }
30
+ if (!cache.sourceFileHashes) {
31
+ cache.sourceFileHashes = {};
32
+ }
33
+ return cache;
34
+ } catch (err) {
35
+ return {
36
+ lastBuildTime: 0,
37
+ sourceModTime: 0,
38
+ docModTime: 0,
39
+ fileHashes: {},
40
+ sourceFileHashes: {}
41
+ };
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Save the cache file
47
+ */
48
+ export function saveCache(cacheFile, cache) {
49
+ // Ensure fileHashes is always present
50
+ if (!cache.fileHashes) {
51
+ cache.fileHashes = {};
52
+ }
53
+ if (!cache.sourceFileHashes) {
54
+ cache.sourceFileHashes = {};
55
+ }
56
+ writeFileSync(cacheFile, JSON.stringify(cache, null, 2), 'utf-8');
57
+ }
58
+
59
+ /**
60
+ * Prime the docs cache using the currently checked-in documentation.
61
+ * This lets future runs rely on hash comparisons even if git status is dirty.
62
+ */
63
+ export function primeCacheFromExistingDocs(config) {
64
+ const {
65
+ cacheFile,
66
+ docsDir,
67
+ srcDir,
68
+ getLatestSourceModTime,
69
+ getLatestDocModTime,
70
+ getExistingDocHashes,
71
+ getSourceFileHashes
72
+ } = config;
73
+
74
+ const currentDocHashes = getExistingDocHashes(docsDir);
75
+ const currentSourceHashes = getSourceFileHashes(srcDir);
76
+
77
+ const docHashesObj = {};
78
+ for (const [relativePath, hash] of currentDocHashes.entries()) {
79
+ docHashesObj[relativePath] = hash;
80
+ }
81
+
82
+ const sourceHashesObj = {};
83
+ for (const [relativePath, hash] of currentSourceHashes.entries()) {
84
+ sourceHashesObj[relativePath] = hash;
85
+ }
86
+
87
+ const ignorePatterns = [
88
+ /\.test\.(ts|tsx)$/,
89
+ /\.spec\.(ts|tsx)$/,
90
+ /__tests__/,
91
+ /\/test\//,
92
+ /\/tests\//
93
+ ];
94
+
95
+ const cache = {
96
+ lastBuildTime: Date.now(),
97
+ sourceModTime: getLatestSourceModTime(srcDir, ignorePatterns),
98
+ docModTime: getLatestDocModTime(docsDir),
99
+ fileHashes: docHashesObj,
100
+ sourceFileHashes: sourceHashesObj
101
+ };
102
+
103
+ saveCache(cacheFile, cache);
104
+ }
105
+
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Content normalization utilities for documentation comparison
5
+ */
6
+
7
+ import { readFileSync } from 'fs';
8
+ import { join } from 'path';
9
+
10
+ /**
11
+ * Sort markdown list items for deterministic comparison
12
+ */
13
+ export function sortMarkdownListItems(text) {
14
+ // Match markdown list sections (lines starting with - or *)
15
+ const lines = text.split('\n');
16
+ const sortedLines = [];
17
+ let currentList = [];
18
+ let inList = false;
19
+
20
+ for (const line of lines) {
21
+ const isListItem = /^\s*[-*]\s+/.test(line);
22
+
23
+ if (isListItem) {
24
+ if (!inList && currentList.length > 0) {
25
+ // Flush previous non-list content
26
+ sortedLines.push(...currentList);
27
+ currentList = [];
28
+ }
29
+ inList = true;
30
+ currentList.push(line);
31
+ } else {
32
+ if (inList && currentList.length > 0) {
33
+ // Sort and flush list
34
+ currentList.sort();
35
+ sortedLines.push(...currentList);
36
+ currentList = [];
37
+ }
38
+ inList = false;
39
+ currentList.push(line);
40
+ }
41
+ }
42
+
43
+ // Flush remaining content
44
+ if (currentList.length > 0) {
45
+ if (inList) {
46
+ currentList.sort();
47
+ }
48
+ sortedLines.push(...currentList);
49
+ }
50
+
51
+ return sortedLines.join('\n');
52
+ }
53
+
54
+ /**
55
+ * Normalize markdown link references for deterministic comparison
56
+ */
57
+ export function normalizeMarkdownLinks(text) {
58
+ // Extract and sort link references [id]: url "title"
59
+ const linkRefPattern = /^\[([^\]]+)\]:\s*(.+)$/gm;
60
+ const links = [];
61
+ let match;
62
+
63
+ while ((match = linkRefPattern.exec(text)) !== null) {
64
+ links.push(match[0]);
65
+ }
66
+
67
+ if (links.length > 0) {
68
+ // Sort links by ID
69
+ links.sort();
70
+ // Replace all link references with sorted version
71
+ let normalized = text.replace(linkRefPattern, 'LINKREF');
72
+ // Append sorted links at the end
73
+ normalized = normalized.replace(/LINKREF/g, () => links.shift() || 'LINKREF');
74
+ return normalized;
75
+ }
76
+
77
+ return text;
78
+ }
79
+
80
+ /**
81
+ * Normalize "Defined in" links emitted by TypeDoc so that branch/remote differences
82
+ * don't cause hash mismatches between environments.
83
+ */
84
+ export function normalizeDefinedInLinks(text) {
85
+ const definedInPattern = /\[(packages\/core\/[^\]]+?:\d+)\]\((https?:\/\/[^(]+?#L\d+)\)/g;
86
+ return text.replace(definedInPattern, (_match, displayText) => displayText);
87
+ }
88
+
89
+ /**
90
+ * Normalize content for comparison (remove trailing whitespace, normalize line endings, version numbers, timestamps)
91
+ */
92
+ export function normalizeContent(content) {
93
+ let normalized = content
94
+ .replace(/\r\n/g, '\n') // Normalize line endings
95
+ .replace(/\r/g, '\n') // Handle old Mac line endings
96
+ .replace(/[ \t]+$/gm, '') // Remove trailing spaces/tabs
97
+ .replace(/\n{3,}/g, '\n\n'); // Normalize multiple blank lines
98
+
99
+ // Remove version numbers from TypeDoc-generated content
100
+ // TypeDoc includes version like "@jmruthers/pace-core@0.5.158"
101
+ // We normalize this to "@jmruthers/pace-core@VERSION" so version changes don't trigger updates
102
+ // This allows docs to remain unchanged when only the version number changes
103
+ normalized = normalized.replace(/@jmruthers\/pace-core@[\d.]+/g, '@jmruthers/pace-core@VERSION');
104
+ normalized = normalized.replace(/version\s+[\d.]+/gi, 'version VERSION');
105
+ // Also handle any other version patterns that might appear
106
+ normalized = normalized.replace(/\b[\d]+\.[\d]+\.[\d]+/g, 'VERSION');
107
+
108
+ // Remove timestamps and dates that might be generated dynamically
109
+ normalized = normalized.replace(/\d{4}-\d{2}-\d{2}/g, 'DATE'); // YYYY-MM-DD
110
+ normalized = normalized.replace(/\d{2}\/\d{2}\/\d{4}/g, 'DATE'); // MM/DD/YYYY
111
+ normalized = normalized.replace(/\d{2}:\d{2}:\d{2}/g, 'TIME'); // HH:MM:SS
112
+ normalized = normalized.replace(/Generated\s+on[^\n]*/gi, 'Generated on DATE');
113
+ normalized = normalized.replace(/Last\s+updated[^\n]*/gi, 'Last updated DATE');
114
+ normalized = normalized.replace(/Updated\s+[^\n]*/gi, 'Updated DATE');
115
+
116
+ // Remove any git commit hashes or SHAs that might appear
117
+ normalized = normalized.replace(/\b[0-9a-f]{7,40}\b/gi, 'HASH');
118
+
119
+ // Remove any ISO timestamps
120
+ normalized = normalized.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[.\d]*Z?/g, 'TIMESTAMP');
121
+
122
+ // Normalize whitespace more aggressively
123
+ normalized = normalized.replace(/[ \t]+/g, ' '); // Multiple spaces/tabs to single space
124
+ normalized = normalized.replace(/ \n/g, '\n'); // Remove trailing spaces before newlines
125
+
126
+ // Sort markdown lists for deterministic comparison
127
+ normalized = sortMarkdownListItems(normalized);
128
+
129
+ // Normalize markdown link references
130
+ normalized = normalizeMarkdownLinks(normalized);
131
+
132
+ // Normalize "Defined in" GitHub links
133
+ normalized = normalizeDefinedInLinks(normalized);
134
+
135
+ return normalized.trim();
136
+ }
137
+
138
+ /**
139
+ * Get current package version from package.json
140
+ */
141
+ export function getPackageVersion(packageRoot) {
142
+ try {
143
+ const packageJsonPath = join(packageRoot, 'package.json');
144
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
145
+ return packageJson.version || '';
146
+ } catch (err) {
147
+ return '';
148
+ }
149
+ }
150
+
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * File system utilities for documentation build
5
+ */
6
+
7
+ import { existsSync, statSync, readdirSync } from 'fs';
8
+ import { join, relative } from 'path';
9
+
10
+ /**
11
+ * Recursively scan directory for files matching pattern
12
+ */
13
+ export function scanDirectory(dir, extensions, ignorePatterns = [], baseDir = null) {
14
+ const files = [];
15
+ const base = baseDir || dir;
16
+
17
+ function scan(currentDir) {
18
+ if (!existsSync(currentDir)) {
19
+ return;
20
+ }
21
+
22
+ try {
23
+ const items = readdirSync(currentDir, { withFileTypes: true });
24
+
25
+ for (const item of items) {
26
+ const fullPath = join(currentDir, item.name);
27
+
28
+ // Skip ignored patterns - test against relative path from base
29
+ const shouldIgnore = ignorePatterns.length > 0 && ignorePatterns.some(pattern => {
30
+ const relativePath = relative(base, fullPath);
31
+ return pattern.test(relativePath) || pattern.test(item.name);
32
+ });
33
+
34
+ if (shouldIgnore) {
35
+ continue;
36
+ }
37
+
38
+ if (item.isDirectory() && !item.name.startsWith('.') && item.name !== 'node_modules') {
39
+ scan(fullPath);
40
+ } else if (item.isFile()) {
41
+ const ext = item.name.substring(item.name.lastIndexOf('.'));
42
+ if (extensions.includes(ext)) {
43
+ files.push(fullPath);
44
+ }
45
+ }
46
+ }
47
+ } catch (err) {
48
+ // Skip directories we can't read
49
+ }
50
+ }
51
+
52
+ scan(dir);
53
+ return files;
54
+ }
55
+
56
+ /**
57
+ * Get the most recent modification time of all source files
58
+ */
59
+ export function getLatestSourceModTime(srcDir, ignorePatterns = []) {
60
+ const sourceFiles = scanDirectory(srcDir, ['.ts', '.tsx'], ignorePatterns, srcDir);
61
+
62
+ let latestTime = 0;
63
+ for (const filePath of sourceFiles) {
64
+ try {
65
+ const stats = statSync(filePath);
66
+ if (stats.mtimeMs > latestTime) {
67
+ latestTime = stats.mtimeMs;
68
+ }
69
+ } catch (err) {
70
+ // File might have been deleted, skip it
71
+ }
72
+ }
73
+
74
+ return latestTime;
75
+ }
76
+
77
+ /**
78
+ * Get the most recent modification time of generated docs
79
+ */
80
+ export function getLatestDocModTime(docsDir) {
81
+ if (!existsSync(docsDir)) {
82
+ return 0;
83
+ }
84
+
85
+ const docFiles = scanDirectory(docsDir, ['.md']);
86
+
87
+ if (docFiles.length === 0) {
88
+ return 0;
89
+ }
90
+
91
+ let latestTime = 0;
92
+ for (const filePath of docFiles) {
93
+ try {
94
+ const stats = statSync(filePath);
95
+ if (stats.mtimeMs > latestTime) {
96
+ latestTime = stats.mtimeMs;
97
+ }
98
+ } catch (err) {
99
+ // File might have been deleted, skip it
100
+ }
101
+ }
102
+
103
+ return latestTime;
104
+ }
105
+
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Git utilities for documentation build
5
+ */
6
+
7
+ import { execSync } from 'child_process';
8
+ import { existsSync } from 'fs';
9
+ import { scanDirectory } from './file-utils.js';
10
+
11
+ /**
12
+ * Determine if we're inside a git repository
13
+ */
14
+ export function isGitRepository(repoRoot) {
15
+ try {
16
+ execSync('git rev-parse --is-inside-work-tree', {
17
+ cwd: repoRoot,
18
+ stdio: 'pipe'
19
+ });
20
+ return true;
21
+ } catch (err) {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Check if git reports any relevant source changes
28
+ */
29
+ export function hasGitTrackedSourceChanges(repoRoot, docsRelevantPaths) {
30
+ if (!isGitRepository(repoRoot)) {
31
+ return true; // Without git context, err on the side of rebuilding
32
+ }
33
+
34
+ try {
35
+ const status = execSync(`git status --porcelain -- ${docsRelevantPaths.join(' ')}`.trim(), {
36
+ cwd: repoRoot,
37
+ encoding: 'utf-8',
38
+ stdio: 'pipe'
39
+ }).trim();
40
+
41
+ return status.length > 0;
42
+ } catch (err) {
43
+ console.log('⚠️ Unable to determine git status for docs generation, running TypeDoc to be safe.');
44
+ return true;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * If we don't have a cache yet but the repo is clean and docs exist, we can skip
50
+ */
51
+ export function shouldSkipDueToCleanGitState(repoRoot, docsDir, docsRelevantPaths) {
52
+ if (!existsSync(docsDir)) {
53
+ return false;
54
+ }
55
+
56
+ const existingDocs = scanDirectory(docsDir, ['.md']);
57
+ if (existingDocs.length === 0) {
58
+ return false;
59
+ }
60
+
61
+ if (hasGitTrackedSourceChanges(repoRoot, docsRelevantPaths)) {
62
+ return false;
63
+ }
64
+
65
+ console.log('✅ Git working tree is clean for documentation-related sources.');
66
+ console.log(' Assuming checked-in docs are up to date, skipping TypeDoc run.');
67
+ return true;
68
+ }
69
+
70
+ /**
71
+ * Get git status of docs directory
72
+ */
73
+ export function getGitStatus(packageRoot, directory) {
74
+ try {
75
+ const result = execSync(`git status --porcelain ${directory}`, {
76
+ cwd: packageRoot,
77
+ encoding: 'utf-8',
78
+ stdio: 'pipe'
79
+ });
80
+ return result.trim().split('\n').filter(line => line.trim());
81
+ } catch (err) {
82
+ // Not a git repo or git not available
83
+ return [];
84
+ }
85
+ }
86
+