@jmruthers/pace-core 0.6.10 → 0.6.12

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 (1500) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +1 -0
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/DataTable-AQAHSFLM.js +17 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-6OQXYT67.js +6 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/audit-HI2DHUVU.js +4 -0
  29. package/dist/auth-JvdRVaud.d.ts +49 -0
  30. package/dist/chunk-2DL2WSOE.js +327 -0
  31. package/dist/chunk-2GBDPPUC.js +61 -0
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/chunk-AP5FG7W4.js +2159 -0
  34. package/dist/chunk-CU2BU2MQ.js +2 -0
  35. package/dist/chunk-D6BMFMQZ.js +200 -0
  36. package/dist/chunk-ENLXB7GP.js +721 -0
  37. package/dist/chunk-GHCUP64P.js +105 -0
  38. package/dist/chunk-H6RTU4DZ.js +1098 -0
  39. package/dist/chunk-HQTYP6BX.js +6468 -0
  40. package/dist/chunk-M7QE7XOA.js +529 -0
  41. package/dist/chunk-MVVWZ7JV.js +1329 -0
  42. package/dist/chunk-NJ7FGQWB.js +811 -0
  43. package/dist/chunk-QRYSEPHB.js +429 -0
  44. package/dist/chunk-QWIG36BZ.js +264 -0
  45. package/dist/chunk-S57OLCLO.js +2946 -0
  46. package/dist/chunk-VFLR5K2H.js +23 -0
  47. package/dist/chunk-XOJME5T7.js +407 -0
  48. package/dist/chunk-XPFVT3GN.js +492 -0
  49. package/dist/chunk-Y2LWSLLB.js +9614 -0
  50. package/dist/chunk-YFGNMB67.js +2390 -0
  51. package/dist/components.d.ts +10 -9
  52. package/dist/components.js +20 -17
  53. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  54. package/dist/eslint-rules/index.cjs +3 -0
  55. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  56. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  57. package/dist/event-BfCox3N2.d.ts +265 -0
  58. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  59. package/dist/functions-hF5ImHCr.d.ts +208 -0
  60. package/dist/hooks.d.ts +22 -9
  61. package/dist/hooks.js +35 -25
  62. package/dist/icons/index.d.ts +1 -0
  63. package/dist/icons/index.js +1 -0
  64. package/dist/index.d.ts +69 -180
  65. package/dist/index.js +319 -342
  66. package/dist/pagination-BW1mqywp.d.ts +201 -0
  67. package/dist/providers.d.ts +6 -5
  68. package/dist/providers.js +6 -3
  69. package/dist/rbac/index.d.ts +133 -148
  70. package/dist/rbac/index.js +12 -9
  71. package/dist/theming/runtime.d.ts +19 -2
  72. package/dist/theming/runtime.js +1 -1
  73. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  74. package/dist/types-Besvoyzb.d.ts +55 -0
  75. package/dist/types-CGHrxfqc.d.ts +114 -0
  76. package/dist/types.d.ts +19 -12
  77. package/dist/types.js +1 -0
  78. package/dist/usePublicPageContext-BQrHf95t.d.ts +4367 -0
  79. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  80. package/dist/utils.d.ts +163 -145
  81. package/dist/utils.js +45 -27
  82. package/docs/api/@jmruthers/namespaces/DialogPortal/README.md +14 -0
  83. package/docs/api/@jmruthers/namespaces/DialogPortal/variables/displayName.md +11 -0
  84. package/docs/api/README.md +6 -2
  85. package/docs/api/_media/README.md +186 -0
  86. package/docs/api/classes/ColumnFactory.md +225 -0
  87. package/docs/api/classes/Logger.md +246 -0
  88. package/docs/api/classes/RBACAuditManager.md +299 -0
  89. package/docs/api/classes/RBACCache.md +389 -0
  90. package/docs/api/classes/RBACEngine.md +181 -0
  91. package/docs/api/classes/SecureSupabaseClient.md +168 -0
  92. package/docs/api/classes/StorageUtils.md +324 -0
  93. package/docs/api/enumerations/FileCategory.md +137 -0
  94. package/docs/api/enumerations/LogLevel.md +43 -0
  95. package/docs/api/enumerations/RBACErrorCode.md +169 -0
  96. package/docs/api/enumerations/RPCFunction.md +89 -0
  97. package/docs/api/functions/AccessDenied.md +30 -0
  98. package/docs/api/functions/AppSwitcher.md +21 -0
  99. package/docs/api/functions/Badge.md +42 -0
  100. package/docs/api/functions/ContextSelector.md +43 -0
  101. package/docs/api/functions/DataTable.md +36 -0
  102. package/docs/api/functions/DatePickerWithTimezone.md +28 -0
  103. package/docs/api/functions/DialogBody.md +24 -0
  104. package/docs/api/functions/DialogFooter.md +24 -0
  105. package/docs/api/functions/DialogHeader.md +24 -0
  106. package/docs/api/functions/ErrorBoundaryProvider.md +28 -0
  107. package/docs/api/functions/EventServiceProvider.md +28 -0
  108. package/docs/api/functions/FileDisplay.md +25 -0
  109. package/docs/api/functions/FileUpload.md +21 -0
  110. package/docs/api/functions/Form.md +50 -0
  111. package/docs/api/functions/FormField.md +102 -0
  112. package/docs/api/functions/Header.md +21 -0
  113. package/docs/api/functions/InactivityServiceProvider.md +28 -0
  114. package/docs/api/functions/InactivityWarningModal.md +21 -0
  115. package/docs/api/functions/Input.md +49 -0
  116. package/docs/api/functions/NavigationGuard.md +31 -0
  117. package/docs/api/functions/OrganisationServiceProvider.md +28 -0
  118. package/docs/api/functions/PaceAppLayout.md +169 -0
  119. package/docs/api/functions/PasswordChangeForm.md +21 -0
  120. package/docs/api/functions/ProtectedRoute.md +37 -0
  121. package/docs/api/functions/PublicPageFooter.md +21 -0
  122. package/docs/api/functions/PublicPageHeader.md +21 -0
  123. package/docs/api/functions/PublicPageLayout.md +33 -0
  124. package/docs/api/functions/PublicPageProvider.md +30 -0
  125. package/docs/api/functions/Textarea.md +49 -0
  126. package/docs/api/functions/Toaster.md +34 -0
  127. package/docs/api/functions/UnifiedAuthProvider.md +28 -0
  128. package/docs/api/functions/applyPalette.md +33 -0
  129. package/docs/api/functions/archiveFile.md +47 -0
  130. package/docs/api/functions/average.md +63 -0
  131. package/docs/api/functions/buildAppUrl.md +46 -0
  132. package/docs/api/functions/clearInFlightRequests.md +17 -0
  133. package/docs/api/functions/clearPalette.md +18 -0
  134. package/docs/api/functions/clearPublicEventCache.md +18 -0
  135. package/docs/api/functions/clearPublicFileDisplayCache.md +18 -0
  136. package/docs/api/functions/clearPublicLogoCache.md +18 -0
  137. package/docs/api/functions/cn.md +21 -0
  138. package/docs/api/functions/count.md +56 -0
  139. package/docs/api/functions/createAuditManager.md +45 -0
  140. package/docs/api/functions/createBaseClient.md +75 -0
  141. package/docs/api/functions/createLogger.md +95 -0
  142. package/docs/api/functions/createRBACConfig.md +21 -0
  143. package/docs/api/functions/createRBACEngine.md +33 -0
  144. package/docs/api/functions/createRBACExpressMiddleware.md +84 -0
  145. package/docs/api/functions/createRBACMiddleware.md +88 -0
  146. package/docs/api/functions/createSecureClient.md +80 -0
  147. package/docs/api/functions/createSecureDataAccess.md +39 -0
  148. package/docs/api/functions/deleteFile.md +33 -0
  149. package/docs/api/functions/disablePerformanceMonitoring.md +17 -0
  150. package/docs/api/functions/downloadFile.md +33 -0
  151. package/docs/api/functions/emitAuditEvent.md +27 -0
  152. package/docs/api/functions/enablePerformanceMonitoring.md +17 -0
  153. package/docs/api/functions/err.md +23 -0
  154. package/docs/api/functions/exportToCSV.md +56 -0
  155. package/docs/api/functions/exportToCSVWithTableRows.md +46 -0
  156. package/docs/api/functions/extractEventCodeFromPath.md +24 -0
  157. package/docs/api/functions/extractFileMetadata.md +33 -0
  158. package/docs/api/functions/formatCompactNumber.md +27 -0
  159. package/docs/api/functions/formatCurrency.md +31 -0
  160. package/docs/api/functions/formatDate.md +23 -0
  161. package/docs/api/functions/formatDateTime.md +24 -0
  162. package/docs/api/functions/formatFileSize.md +23 -0
  163. package/docs/api/functions/formatInTimeZone.md +46 -0
  164. package/docs/api/functions/formatNumber.md +31 -0
  165. package/docs/api/functions/formatPercent.md +64 -0
  166. package/docs/api/functions/formatTime.md +24 -0
  167. package/docs/api/functions/formatTimeInTimeZone.md +40 -0
  168. package/docs/api/functions/fromSupabaseClient.md +49 -0
  169. package/docs/api/functions/fromZonedTime.md +41 -0
  170. package/docs/api/functions/generateCSVContent.md +55 -0
  171. package/docs/api/functions/generateFilePath.md +29 -0
  172. package/docs/api/functions/generateFileUrlsBatch.md +33 -0
  173. package/docs/api/functions/generatePublicRoutePath.md +27 -0
  174. package/docs/api/functions/generateUniqueFileName.md +24 -0
  175. package/docs/api/functions/getAccessLevel.md +48 -0
  176. package/docs/api/functions/getAllAppPorts.md +19 -0
  177. package/docs/api/functions/getAllStylePaths.md +15 -0
  178. package/docs/api/functions/getAppConfig.md +17 -0
  179. package/docs/api/functions/getAppPort.md +34 -0
  180. package/docs/api/functions/getBucketName.md +27 -0
  181. package/docs/api/functions/getCurrentAppId.md +17 -0
  182. package/docs/api/functions/getCurrentAppName.md +17 -0
  183. package/docs/api/functions/getFileSizeLimit.md +23 -0
  184. package/docs/api/functions/getGlobalAuditManager.md +19 -0
  185. package/docs/api/functions/getInFlightRequestCount.md +19 -0
  186. package/docs/api/functions/getPerformanceMetrics.md +17 -0
  187. package/docs/api/functions/getPerformanceSummary.md +17 -0
  188. package/docs/api/functions/getPermissionMap.md +52 -0
  189. package/docs/api/functions/getPublicEventCacheStats.md +25 -0
  190. package/docs/api/functions/getPublicFileDisplayCacheStats.md +25 -0
  191. package/docs/api/functions/getPublicLogoCacheStats.md +25 -0
  192. package/docs/api/functions/getPublicUrl.md +39 -0
  193. package/docs/api/functions/getRBACConfig.md +15 -0
  194. package/docs/api/functions/getRBACLogger.md +15 -0
  195. package/docs/api/functions/getRoleContext.md +31 -0
  196. package/docs/api/functions/getSignedUrl.md +34 -0
  197. package/docs/api/functions/getStylePath.md +21 -0
  198. package/docs/api/functions/getTimeZoneDifference.md +40 -0
  199. package/docs/api/functions/getTimezoneAbbreviation.md +40 -0
  200. package/docs/api/functions/getUserTimeZone.md +26 -0
  201. package/docs/api/functions/hasAllPermissions.md +41 -0
  202. package/docs/api/functions/hasAnyPermission.md +41 -0
  203. package/docs/api/functions/isDebugMode.md +15 -0
  204. package/docs/api/functions/isDevelopmentMode.md +15 -0
  205. package/docs/api/functions/isErr.md +29 -0
  206. package/docs/api/functions/isOk.md +29 -0
  207. package/docs/api/functions/isPerformanceMonitoringEnabled.md +17 -0
  208. package/docs/api/functions/isPermitted.md +58 -0
  209. package/docs/api/functions/isPermittedCached.md +36 -0
  210. package/docs/api/functions/isRBACInitialized.md +19 -0
  211. package/docs/api/functions/isSecureClient.md +38 -0
  212. package/docs/api/functions/isValidPermission.md +27 -0
  213. package/docs/api/functions/listFiles.md +29 -0
  214. package/docs/api/functions/max.md +63 -0
  215. package/docs/api/functions/min.md +63 -0
  216. package/docs/api/functions/ok.md +29 -0
  217. package/docs/api/functions/parseAndNormalizeEventColours.md +105 -0
  218. package/docs/api/functions/recordAuditEvent.md +23 -0
  219. package/docs/api/functions/recordPermissionCheck.md +31 -0
  220. package/docs/api/functions/resetPerformanceMetrics.md +17 -0
  221. package/docs/api/functions/resolveAppContext.md +27 -0
  222. package/docs/api/functions/roundToNearestMinutes.md +41 -0
  223. package/docs/api/functions/sanitizeFormData.md +49 -0
  224. package/docs/api/functions/sanitizeHtml.md +39 -0
  225. package/docs/api/functions/sanitizeUserInput.md +27 -0
  226. package/docs/api/functions/setAppConfig.md +23 -0
  227. package/docs/api/functions/setGlobalAuditManager.md +25 -0
  228. package/docs/api/functions/setupRBAC.md +31 -0
  229. package/docs/api/functions/sum.md +63 -0
  230. package/docs/api/functions/toZonedTime.md +41 -0
  231. package/docs/api/functions/uploadFile.md +32 -0
  232. package/docs/api/functions/useAccessLevel.md +71 -0
  233. package/docs/api/functions/useAccessibleApps.md +55 -0
  234. package/docs/api/functions/useAppConfig.md +20 -0
  235. package/docs/api/functions/useAuthService.md +15 -0
  236. package/docs/api/functions/useCan.md +99 -0
  237. package/docs/api/functions/useEventService.md +15 -0
  238. package/docs/api/functions/useEventTheme.md +26 -0
  239. package/docs/api/functions/useEvents.md +45 -0
  240. package/docs/api/functions/useFileReference.md +264 -0
  241. package/docs/api/functions/useFileReferenceById.md +63 -0
  242. package/docs/api/functions/useFileReferenceForRecord.md +129 -0
  243. package/docs/api/functions/useFilesByCategory.md +80 -0
  244. package/docs/api/functions/useFormDialog.md +62 -0
  245. package/docs/api/functions/useInactivityService.md +15 -0
  246. package/docs/api/functions/useInactivityTracker.md +21 -0
  247. package/docs/api/functions/useIsPublicPage.md +19 -0
  248. package/docs/api/functions/useMultiplePermissions.md +88 -0
  249. package/docs/api/functions/useOptionalEvents.md +31 -0
  250. package/docs/api/functions/useOrganisationPermissions.md +27 -0
  251. package/docs/api/functions/useOrganisationSecurity.md +15 -0
  252. package/docs/api/functions/useOrganisationService.md +15 -0
  253. package/docs/api/functions/useOrganisations.md +48 -0
  254. package/docs/api/functions/usePermissions.md +130 -0
  255. package/docs/api/functions/usePublicEvent.md +36 -0
  256. package/docs/api/functions/usePublicEventCode.md +32 -0
  257. package/docs/api/functions/usePublicEventLogo.md +48 -0
  258. package/docs/api/functions/usePublicFileDisplay.md +54 -0
  259. package/docs/api/functions/usePublicPageContext.md +19 -0
  260. package/docs/api/functions/usePublicRouteParams.md +31 -0
  261. package/docs/api/functions/useRBAC.md +21 -0
  262. package/docs/api/functions/useResolvedScope.md +46 -0
  263. package/docs/api/functions/useResourcePermissions.md +25 -0
  264. package/docs/api/functions/useRoleManagement.md +121 -0
  265. package/docs/api/functions/useSecureSupabase.md +51 -0
  266. package/docs/api/functions/useSessionRestoration.md +15 -0
  267. package/docs/api/functions/useSessionTracking.md +62 -0
  268. package/docs/api/functions/useToast.md +83 -0
  269. package/docs/api/functions/useUnifiedAuth.md +24 -0
  270. package/docs/api/functions/useZodForm.md +27 -0
  271. package/docs/api/functions/validateFileSize.md +31 -0
  272. package/docs/api/functions/warnIfInsecureClient.md +40 -0
  273. package/docs/api/functions/withAccessLevelGuard.md +67 -0
  274. package/docs/api/functions/withPermissionGuard.md +73 -0
  275. package/docs/api/functions/withRoleGuard.md +86 -0
  276. package/docs/api/globals.md +502 -0
  277. package/docs/api/interfaces/AccessDeniedProps.md +87 -0
  278. package/docs/api/interfaces/AccessibleApp.md +41 -0
  279. package/docs/api/interfaces/AddressFieldProps.md +195 -0
  280. package/docs/api/interfaces/AddressFieldRef.md +67 -0
  281. package/docs/api/interfaces/AggregateConfig.md +35 -0
  282. package/docs/api/interfaces/AppSwitcherProps.md +51 -0
  283. package/docs/api/interfaces/AuthSessionData.md +27 -0
  284. package/docs/api/interfaces/AutocompleteOptions.md +61 -0
  285. package/docs/api/interfaces/AvatarProps.md +97 -0
  286. package/docs/api/interfaces/BadgeProps.md +30 -0
  287. package/docs/api/interfaces/BuildAppUrlOptions.md +41 -0
  288. package/docs/api/interfaces/ButtonProps.md +46 -0
  289. package/docs/api/interfaces/CalendarProps.md +60 -0
  290. package/docs/api/interfaces/CardProps.md +56 -0
  291. package/docs/api/interfaces/ColorPalette.md +13 -0
  292. package/docs/api/interfaces/ColorShade.md +58 -0
  293. package/docs/api/interfaces/ContextSelectorProps.md +131 -0
  294. package/docs/api/interfaces/DataRecord.md +16 -0
  295. package/docs/api/interfaces/DataTableAction.md +198 -0
  296. package/docs/api/interfaces/DataTableColumn.md +422 -0
  297. package/docs/api/interfaces/DataTableProps.md +511 -0
  298. package/docs/api/interfaces/DataTableToolbarButton.md +75 -0
  299. package/docs/api/interfaces/DatePickerWithTimezoneProps.md +75 -0
  300. package/docs/api/interfaces/DialogBodyProps.md +55 -0
  301. package/docs/api/interfaces/DialogCloseProps.md +25 -0
  302. package/docs/api/interfaces/DialogContentProps.md +160 -0
  303. package/docs/api/interfaces/DialogFooterProps.md +25 -0
  304. package/docs/api/interfaces/DialogHeaderProps.md +25 -0
  305. package/docs/api/interfaces/DialogPortalProps.md +19 -0
  306. package/docs/api/interfaces/DialogProps.md +53 -0
  307. package/docs/api/interfaces/DialogTriggerProps.md +53 -0
  308. package/docs/api/interfaces/EmptyStateConfig.md +55 -0
  309. package/docs/api/interfaces/ErrorBoundaryProps.md +131 -0
  310. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +31 -0
  311. package/docs/api/interfaces/ErrorBoundaryState.md +61 -0
  312. package/docs/api/interfaces/EventAppRoleData.md +54 -0
  313. package/docs/api/interfaces/ExportColumn.md +69 -0
  314. package/docs/api/interfaces/ExportOptions.md +109 -0
  315. package/docs/api/interfaces/FileDisplayProps.md +192 -0
  316. package/docs/api/interfaces/FileMetadata.md +97 -0
  317. package/docs/api/interfaces/FileReference.md +89 -0
  318. package/docs/api/interfaces/FileSizeLimits.md +13 -0
  319. package/docs/api/interfaces/FileUploadOptions.md +107 -0
  320. package/docs/api/interfaces/FooterProps.md +37 -0
  321. package/docs/api/interfaces/FormFieldProps.md +171 -0
  322. package/docs/api/interfaces/FormProps.md +93 -0
  323. package/docs/api/interfaces/GrantEventAppRoleParams.md +97 -0
  324. package/docs/api/interfaces/ImportSummary.md +49 -0
  325. package/docs/api/interfaces/InactivityWarningModalProps.md +87 -0
  326. package/docs/api/interfaces/InputProps.md +46 -0
  327. package/docs/api/interfaces/InvalidScopeError.md +37 -0
  328. package/docs/api/interfaces/LabelProps.md +85 -0
  329. package/docs/api/interfaces/LoggerConfig.md +51 -0
  330. package/docs/api/interfaces/LoginFormProps.md +146 -0
  331. package/docs/api/interfaces/MissingUserContextError.md +37 -0
  332. package/docs/api/interfaces/NavigationGuardProps.md +109 -0
  333. package/docs/api/interfaces/NavigationItem.md +91 -0
  334. package/docs/api/interfaces/NavigationMenuProps.md +169 -0
  335. package/docs/api/interfaces/Organisation.md +105 -0
  336. package/docs/api/interfaces/OrganisationContextRequiredError.md +37 -0
  337. package/docs/api/interfaces/OrganisationMembership.md +105 -0
  338. package/docs/api/interfaces/OrganisationSecurityError.md +49 -0
  339. package/docs/api/interfaces/PaceAppLayoutPermissionConfig.md +127 -0
  340. package/docs/api/interfaces/PaceAppLayoutRouteConfigItem.md +91 -0
  341. package/docs/api/interfaces/PaceAppLayoutRoutingConfig.md +79 -0
  342. package/docs/api/interfaces/PaceLoginPageProps.md +41 -0
  343. package/docs/api/interfaces/PagePermissionGuardProps.md +143 -0
  344. package/docs/api/interfaces/PaletteData.md +33 -0
  345. package/docs/api/interfaces/ParsedAddress.md +91 -0
  346. package/docs/api/interfaces/PermissionDeniedError.md +37 -0
  347. package/docs/api/interfaces/ProgressProps.md +35 -0
  348. package/docs/api/interfaces/ProtectedRouteProps.md +67 -0
  349. package/docs/api/interfaces/PublicPageFooterProps.md +97 -0
  350. package/docs/api/interfaces/PublicPageHeaderProps.md +99 -0
  351. package/docs/api/interfaces/PublicPageLayoutProps.md +153 -0
  352. package/docs/api/interfaces/RBACAccessValidateParams.md +41 -0
  353. package/docs/api/interfaces/RBACAccessValidateResult.md +33 -0
  354. package/docs/api/interfaces/RBACAuditLogParams.md +65 -0
  355. package/docs/api/interfaces/RBACAuditLogResult.md +41 -0
  356. package/docs/api/interfaces/RBACContext.md +41 -0
  357. package/docs/api/interfaces/RBACError.md +37 -0
  358. package/docs/api/interfaces/RBACLogger.md +97 -0
  359. package/docs/api/interfaces/RBACNotInitializedError.md +37 -0
  360. package/docs/api/interfaces/RBACPageAccessCheckParams.md +57 -0
  361. package/docs/api/interfaces/RBACPerformanceMetrics.md +109 -0
  362. package/docs/api/interfaces/RBACPermissionCheckParams.md +57 -0
  363. package/docs/api/interfaces/RBACPermissionCheckResult.md +41 -0
  364. package/docs/api/interfaces/RBACPermissionsGetParams.md +49 -0
  365. package/docs/api/interfaces/RBACPermissionsGetResult.md +49 -0
  366. package/docs/api/interfaces/RBACResult.md +47 -0
  367. package/docs/api/interfaces/RBACRoleGrantParams.md +49 -0
  368. package/docs/api/interfaces/RBACRoleGrantResult.md +41 -0
  369. package/docs/api/interfaces/RBACRoleRevokeParams.md +49 -0
  370. package/docs/api/interfaces/RBACRoleRevokeResult.md +41 -0
  371. package/docs/api/interfaces/RBACRoleValidateParams.md +41 -0
  372. package/docs/api/interfaces/RBACRoleValidateResult.md +49 -0
  373. package/docs/api/interfaces/RBACRolesListParams.md +41 -0
  374. package/docs/api/interfaces/RBACRolesListResult.md +57 -0
  375. package/docs/api/interfaces/RBACSessionTrackParams.md +57 -0
  376. package/docs/api/interfaces/RBACSessionTrackResult.md +41 -0
  377. package/docs/api/interfaces/ResourcePermissions.md +119 -0
  378. package/docs/api/interfaces/RevokeEventAppRoleParams.md +81 -0
  379. package/docs/api/interfaces/RoleManagementResult.md +41 -0
  380. package/docs/api/interfaces/SessionRestorationLoaderProps.md +29 -0
  381. package/docs/api/interfaces/StorageConfig.md +33 -0
  382. package/docs/api/interfaces/StorageFileInfo.md +57 -0
  383. package/docs/api/interfaces/StorageFileMetadata.md +113 -0
  384. package/docs/api/interfaces/StorageListOptions.md +79 -0
  385. package/docs/api/interfaces/StorageListResult.md +33 -0
  386. package/docs/api/interfaces/StorageUploadOptions.md +81 -0
  387. package/docs/api/interfaces/StorageUploadResult.md +49 -0
  388. package/docs/api/interfaces/StorageUploadSuccess.md +35 -0
  389. package/docs/api/interfaces/StorageUrlOptions.md +49 -0
  390. package/docs/api/interfaces/StyleImport.md +17 -0
  391. package/docs/api/interfaces/SwitchProps.md +30 -0
  392. package/docs/api/interfaces/TabsContentProps.md +13 -0
  393. package/docs/api/interfaces/TabsListProps.md +13 -0
  394. package/docs/api/interfaces/TabsProps.md +13 -0
  395. package/docs/api/interfaces/TabsTriggerProps.md +41 -0
  396. package/docs/api/interfaces/TextareaProps.md +43 -0
  397. package/docs/api/interfaces/ToastActionElement.md +16 -0
  398. package/docs/api/interfaces/ToastProps.md +13 -0
  399. package/docs/api/interfaces/UnifiedAuthProviderProps.md +129 -0
  400. package/docs/api/interfaces/UseAccessibleAppsReturn.md +55 -0
  401. package/docs/api/interfaces/UseFormDialogOptions.md +49 -0
  402. package/docs/api/interfaces/UseFormDialogReturn.md +95 -0
  403. package/docs/api/interfaces/UseInactivityTrackerOptions.md +103 -0
  404. package/docs/api/interfaces/UseInactivityTrackerReturn.md +91 -0
  405. package/docs/api/interfaces/UsePublicEventLogoOptions.md +69 -0
  406. package/docs/api/interfaces/UsePublicEventLogoReturn.md +66 -0
  407. package/docs/api/interfaces/UsePublicEventOptions.md +29 -0
  408. package/docs/api/interfaces/UsePublicEventReturn.md +56 -0
  409. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +39 -0
  410. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +96 -0
  411. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +76 -0
  412. package/docs/api/interfaces/UseResolvedScopeOptions.md +49 -0
  413. package/docs/api/interfaces/UseResolvedScopeReturn.md +39 -0
  414. package/docs/api/interfaces/UseResourcePermissionsOptions.md +29 -0
  415. package/docs/api/interfaces/UserEventAccess.md +92 -0
  416. package/docs/api/interfaces/UserMenuProps.md +69 -0
  417. package/docs/api/interfaces/UserProfile.md +49 -0
  418. package/docs/api/type-aliases/AccessLevel.md +11 -0
  419. package/docs/api/type-aliases/AccessLevelContext.md +14 -0
  420. package/docs/api/type-aliases/AllPermissions.md +11 -0
  421. package/docs/api/type-aliases/ApiError.md +37 -0
  422. package/docs/api/type-aliases/ApiResult.md +19 -0
  423. package/docs/api/type-aliases/AuditEventType.md +11 -0
  424. package/docs/api/type-aliases/BadgeVariant.md +18 -0
  425. package/docs/api/type-aliases/DataTableFeatureConfig.md +14 -0
  426. package/docs/api/type-aliases/DialogSize.md +13 -0
  427. package/docs/api/type-aliases/EventAppRole.md +11 -0
  428. package/docs/api/type-aliases/FileUploadProps.md +15 -0
  429. package/docs/api/type-aliases/GetRowId.md +33 -0
  430. package/docs/api/type-aliases/GlobalErrorHandler.md +35 -0
  431. package/docs/api/type-aliases/GlobalRole.md +11 -0
  432. package/docs/api/type-aliases/ImportHandlerResult.md +13 -0
  433. package/docs/api/type-aliases/NavigationMode.md +13 -0
  434. package/docs/api/type-aliases/Operation.md +11 -0
  435. package/docs/api/type-aliases/OrganisationContextType.md +13 -0
  436. package/docs/api/type-aliases/OrganisationRole.md +11 -0
  437. package/docs/api/type-aliases/PaceAppLayoutProps.md +14 -0
  438. package/docs/api/type-aliases/Permission.md +11 -0
  439. package/docs/api/type-aliases/PermissionCheck.md +46 -0
  440. package/docs/api/type-aliases/PermissionMap.md +11 -0
  441. package/docs/api/type-aliases/PermissionSource.md +13 -0
  442. package/docs/api/type-aliases/RBACConfig.md +13 -0
  443. package/docs/api/type-aliases/RBACFunctionResponse.md +57 -0
  444. package/docs/api/type-aliases/Scope.md +41 -0
  445. package/docs/api/type-aliases/SessionType.md +11 -0
  446. package/docs/api/type-aliases/UUID.md +11 -0
  447. package/docs/api/type-aliases/UnifiedAuthContextType.md +13 -0
  448. package/docs/api/type-aliases/UseFileReferenceForRecordReturn.md +161 -0
  449. package/docs/api/type-aliases/UseFileReferenceOptions.md +35 -0
  450. package/docs/api/type-aliases/UseFileReferenceReturn.md +13 -0
  451. package/docs/api/variables/ALL_PERMISSIONS.md +281 -0
  452. package/docs/api/variables/APP_PATH_MAPPING.md +14 -0
  453. package/docs/api/variables/AddressField.md +41 -0
  454. package/docs/api/variables/Alert.md +11 -0
  455. package/docs/api/variables/AlertDescription.md +11 -0
  456. package/docs/api/variables/AlertTitle.md +11 -0
  457. package/docs/api/variables/Avatar.md +13 -0
  458. package/docs/api/variables/Button.md +31 -0
  459. package/docs/api/variables/CACHE_PATTERNS.md +89 -0
  460. package/docs/api/variables/Calendar.md +74 -0
  461. package/docs/api/variables/Card.md +11 -0
  462. package/docs/api/variables/CardActions.md +11 -0
  463. package/docs/api/variables/CardContent.md +11 -0
  464. package/docs/api/variables/CardDescription.md +11 -0
  465. package/docs/api/variables/CardFooter.md +11 -0
  466. package/docs/api/variables/CardHeader.md +11 -0
  467. package/docs/api/variables/CardTitle.md +11 -0
  468. package/docs/api/variables/Checkbox.md +11 -0
  469. package/docs/api/variables/DEFAULT_APP_PORT_MAP.md +14 -0
  470. package/docs/api/variables/DEFAULT_FILE_SIZE_LIMIT.md +13 -0
  471. package/docs/api/variables/Dialog.md +14 -0
  472. package/docs/api/variables/DialogClose.md +14 -0
  473. package/docs/api/variables/DialogContent.md +28 -0
  474. package/docs/api/variables/DialogDescription.md +14 -0
  475. package/docs/api/variables/DialogPortal.md +14 -0
  476. package/docs/api/variables/DialogTitle.md +14 -0
  477. package/docs/api/variables/DialogTrigger.md +14 -0
  478. package/docs/api/variables/EVENT_APP_PERMISSIONS.md +109 -0
  479. package/docs/api/variables/ErrorBoundary.md +15 -0
  480. package/docs/api/variables/FILE_SIZE_LIMITS.md +13 -0
  481. package/docs/api/variables/Footer.md +11 -0
  482. package/docs/api/variables/GLOBAL_PERMISSIONS.md +29 -0
  483. package/docs/api/variables/Label.md +34 -0
  484. package/docs/api/variables/LoadingSpinner.md +28 -0
  485. package/docs/api/variables/LoginForm.md +34 -0
  486. package/docs/api/variables/NavigationMenu.md +203 -0
  487. package/docs/api/variables/ORGANISATION_PERMISSIONS.md +89 -0
  488. package/docs/api/variables/PAGE_PERMISSIONS.md +93 -0
  489. package/docs/api/variables/PaceLoginPage.md +40 -0
  490. package/docs/api/variables/PagePermissionGuard.md +11 -0
  491. package/docs/api/variables/Progress.md +32 -0
  492. package/docs/api/variables/SECURE_CLIENT_SYMBOL.md +14 -0
  493. package/docs/api/variables/STORAGE_CONFIG.md +13 -0
  494. package/docs/api/variables/Select.md +26 -0
  495. package/docs/api/variables/SelectContent.md +26 -0
  496. package/docs/api/variables/SelectGroup.md +26 -0
  497. package/docs/api/variables/SelectItem.md +26 -0
  498. package/docs/api/variables/SelectLabel.md +26 -0
  499. package/docs/api/variables/SelectSeparator.md +26 -0
  500. package/docs/api/variables/SelectTrigger.md +26 -0
  501. package/docs/api/variables/SelectValue.md +26 -0
  502. package/docs/api/variables/SessionRestorationLoader.md +11 -0
  503. package/docs/api/variables/Switch.md +23 -0
  504. package/docs/api/variables/Table.md +35 -0
  505. package/docs/api/variables/TableBody.md +11 -0
  506. package/docs/api/variables/TableCaption.md +11 -0
  507. package/docs/api/variables/TableCell.md +11 -0
  508. package/docs/api/variables/TableFooter.md +11 -0
  509. package/docs/api/variables/TableHead.md +11 -0
  510. package/docs/api/variables/TableHeader.md +11 -0
  511. package/docs/api/variables/TableRow.md +11 -0
  512. package/docs/api/variables/Tabs.md +25 -0
  513. package/docs/api/variables/TabsContent.md +24 -0
  514. package/docs/api/variables/TabsList.md +25 -0
  515. package/docs/api/variables/TabsTrigger.md +34 -0
  516. package/docs/api/variables/Toast.md +36 -0
  517. package/docs/api/variables/ToastAction.md +32 -0
  518. package/docs/api/variables/ToastClose.md +32 -0
  519. package/docs/api/variables/ToastDescription.md +32 -0
  520. package/docs/api/variables/ToastProvider.md +11 -0
  521. package/docs/api/variables/ToastTitle.md +32 -0
  522. package/docs/api/variables/ToastViewport.md +26 -0
  523. package/docs/api/variables/Tooltip.md +34 -0
  524. package/docs/api/variables/TooltipContent.md +34 -0
  525. package/docs/api/variables/TooltipProvider.md +11 -0
  526. package/docs/api/variables/TooltipRoot.md +11 -0
  527. package/docs/api/variables/TooltipTrigger.md +11 -0
  528. package/docs/api/variables/UserMenu.md +11 -0
  529. package/docs/api/variables/emailSchema.md +13 -0
  530. package/docs/api/variables/logger.md +203 -0
  531. package/docs/api/variables/nameSchema.md +13 -0
  532. package/docs/api/variables/passwordSchema.md +13 -0
  533. package/docs/api/variables/phoneSchema.md +13 -0
  534. package/docs/api/variables/rbacCache.md +16 -0
  535. package/docs/api/variables/styleConfig.md +25 -0
  536. package/docs/api/variables/urlSchema.md +13 -0
  537. package/docs/api-reference/hooks.md +2 -0
  538. package/docs/api-reference/rpc-functions.md +12 -3
  539. package/docs/core-concepts/rbac-system.md +8 -0
  540. package/docs/getting-started/cursor-rules.md +17 -20
  541. package/docs/getting-started/dependencies.md +1 -1
  542. package/docs/getting-started/setup.md +235 -0
  543. package/docs/implementation-guides/authentication.md +27 -0
  544. package/docs/implementation-guides/data-tables.md +184 -3
  545. package/docs/migration/ApiResult-migration.md +25 -0
  546. package/docs/rbac/api-reference.md +33 -31
  547. package/docs/rbac/getting-started.md +7 -0
  548. package/docs/rbac/troubleshooting.md +5 -1
  549. package/docs/standards/0-standards-overview.md +50 -15
  550. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  551. package/docs/standards/2-project-structure-standards.md +33 -16
  552. package/docs/standards/3-architecture-standards.md +41 -1
  553. package/docs/standards/4-code-quality-standards.md +26 -6
  554. package/docs/standards/5-styling-standards.md +35 -1
  555. package/docs/standards/6-security-rbac-standards.md +66 -0
  556. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  557. package/docs/standards/8-testing-documentation-standards.md +31 -0
  558. package/docs/standards/9-operations-standards.md +19 -0
  559. package/docs/standards/README.md +20 -201
  560. package/docs/testing/test-setup-for-consumers.md +2 -0
  561. package/docs/troubleshooting/common-issues.md +17 -1
  562. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  563. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  564. package/eslint-config-pace-core.cjs +20 -0
  565. package/package.json +16 -22
  566. package/scripts/build-docs.js +180 -0
  567. package/scripts/setup.cjs +536 -0
  568. package/scripts/validate.cjs +480 -0
  569. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  570. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  571. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  572. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  573. package/src/__tests__/helpers/test-providers.tsx +37 -39
  574. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  575. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  576. package/src/assets/app-icons/index.test.ts +304 -0
  577. package/src/components/AddressField/AddressField.test.tsx +1 -1
  578. package/src/components/AddressField/AddressField.tsx +238 -212
  579. package/src/components/Button/Button.tsx +1 -1
  580. package/src/components/Card/Card.test.tsx +172 -17
  581. package/src/components/Card/Card.tsx +19 -10
  582. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  583. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  584. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  585. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  586. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  587. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  588. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  589. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  590. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  591. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  592. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  593. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  594. package/src/components/DataTable/DataTable.test.tsx +787 -416
  595. package/src/components/DataTable/DataTable.tsx +12 -12
  596. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  597. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  598. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  599. package/src/components/DataTable/README.md +155 -0
  600. package/src/components/DataTable/TESTING.md +101 -0
  601. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  602. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  603. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  604. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  605. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  606. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  607. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  608. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  609. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  610. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  611. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  612. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  613. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  614. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  615. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  616. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  617. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  618. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +248 -0
  619. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  620. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  621. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  622. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  623. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  624. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  625. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  626. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  627. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  628. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  629. package/src/components/DataTable/hooks/useDataTableScope.test.ts +102 -0
  630. package/src/components/DataTable/hooks/useDataTableScope.ts +125 -0
  631. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  632. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  633. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  634. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  635. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  636. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  637. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  638. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  639. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  640. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  641. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  642. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  643. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  644. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  645. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  646. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  647. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  648. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  649. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  650. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  651. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  652. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  653. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  654. package/src/components/DataTable/index.ts +18 -17
  655. package/src/components/DataTable/keyboard.test.tsx +734 -0
  656. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  657. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  658. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  659. package/src/components/DataTable/styles.test.ts +379 -0
  660. package/src/components/DataTable/styles.ts +0 -1
  661. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  662. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  663. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  664. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  665. package/src/components/DataTable/test-utils.ts +94 -0
  666. package/src/components/DataTable/types/actions.ts +71 -0
  667. package/src/components/DataTable/types/base.ts +39 -0
  668. package/src/components/DataTable/types/columns.ts +125 -0
  669. package/src/components/DataTable/types/export.ts +32 -0
  670. package/src/components/DataTable/types/features.ts +81 -0
  671. package/src/components/DataTable/types/hierarchical.ts +44 -0
  672. package/src/components/DataTable/types/index.ts +43 -0
  673. package/src/components/DataTable/types/pagination.ts +85 -0
  674. package/src/components/DataTable/types/performance.ts +47 -0
  675. package/src/components/DataTable/types/props.ts +62 -0
  676. package/src/components/DataTable/types/rbac.ts +45 -0
  677. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  678. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  679. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  680. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  681. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  682. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  683. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  684. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  685. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  686. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  687. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  688. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  689. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  690. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  691. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  692. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  693. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  694. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  695. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  696. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  697. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  698. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  699. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  700. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  701. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  702. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  703. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  704. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  705. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  706. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  707. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  708. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  709. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  710. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  711. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  712. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  713. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  714. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  715. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  716. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  717. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  718. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  719. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  720. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  721. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  722. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  723. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  724. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  725. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  726. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  727. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  728. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  729. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  730. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  731. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  732. package/src/components/DataTable/utils/csvParse.ts +65 -0
  733. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  734. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  735. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  736. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  737. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  738. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  739. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  740. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  741. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  742. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  743. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  744. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  745. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  746. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  747. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  748. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  749. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  750. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  751. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  752. package/src/components/Dialog/Dialog.test.tsx +896 -89
  753. package/src/components/Dialog/Dialog.tsx +174 -882
  754. package/src/components/Dialog/dialogLock.test.ts +238 -0
  755. package/src/components/Dialog/dialogLock.ts +98 -0
  756. package/src/components/Dialog/index.ts +2 -0
  757. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  758. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  759. package/src/components/Dialog/useDialogLifecycle.test.ts +361 -0
  760. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  761. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  762. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  763. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  764. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  765. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  766. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  767. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  768. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  769. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  770. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  771. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  772. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  773. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  774. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  775. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  776. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  777. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  778. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  779. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  780. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  781. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  782. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  783. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  784. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  785. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  786. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  787. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  788. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  789. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  790. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  791. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  792. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  793. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1442 -0
  794. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  795. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  796. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  797. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  798. package/src/components/FileUpload/FileUpload.tsx +107 -525
  799. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  800. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  801. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  802. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  803. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  804. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  805. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  806. package/src/components/Footer/Footer.test.tsx +6 -292
  807. package/src/components/Footer/Footer.tsx +8 -125
  808. package/src/components/Form/Form.test.tsx +44 -27
  809. package/src/components/Form/Form.tsx +64 -287
  810. package/src/components/Form/useFormPersistence.ts +257 -0
  811. package/src/components/Header/Header.test.tsx +17 -18
  812. package/src/components/Header/Header.tsx +10 -1
  813. package/src/components/Input/Input.tsx +1 -1
  814. package/src/components/Label/Label.test.tsx +1 -1
  815. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  816. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  817. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  818. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  819. package/src/components/NavigationMenu/index.ts +6 -1
  820. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  821. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  822. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  823. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  824. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +109 -70
  825. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  826. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  827. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  828. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  829. package/src/components/PaceAppLayout/useFilteredNavItems.ts +319 -0
  830. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +163 -0
  831. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  832. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  833. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +81 -0
  834. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  835. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  836. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  837. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  838. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  839. package/src/components/Progress/Progress.tsx +1 -2
  840. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  841. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  842. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  843. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  844. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  845. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  846. package/src/components/Select/Select.test.tsx +1 -1
  847. package/src/components/Select/Select.tsx +28 -18
  848. package/src/components/Select/context.test.tsx +56 -0
  849. package/src/components/Select/text.test.tsx +104 -0
  850. package/src/components/Select/text.ts +26 -0
  851. package/src/components/Select/useSelectEvents.test.ts +279 -0
  852. package/src/components/Select/useSelectEvents.ts +87 -0
  853. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  854. package/src/components/Select/useSelectSearch.ts +91 -0
  855. package/src/components/Select/useSelectState.test.ts +268 -0
  856. package/src/components/Select/useSelectState.ts +104 -0
  857. package/src/components/Table/Table.test.tsx +348 -0
  858. package/src/components/Tabs/Tabs.test.tsx +270 -0
  859. package/src/components/Tabs/Tabs.tsx +1 -1
  860. package/src/components/Toast/Toast.test.tsx +420 -0
  861. package/src/components/index.test.ts +346 -0
  862. package/src/constants/performance.test.ts +91 -0
  863. package/src/hooks/ServiceHooks.test.tsx +725 -0
  864. package/src/hooks/hooks.integration.test.tsx +608 -0
  865. package/src/hooks/index.ts +7 -4
  866. package/src/hooks/index.unit.test.ts +220 -0
  867. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  868. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  869. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  870. package/src/hooks/services/useAuth.ts +9 -7
  871. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  872. package/src/hooks/useAddressAutocomplete.ts +90 -75
  873. package/src/hooks/useAppConfig.unit.test.ts +720 -0
  874. package/src/hooks/useComponentPerformance.unit.test.tsx +316 -0
  875. package/src/hooks/useDataTablePerformance.ts +100 -120
  876. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  877. package/src/hooks/useDataTableState.test.ts +170 -0
  878. package/src/hooks/useDebounce.unit.test.ts +157 -0
  879. package/src/hooks/useEventTheme.test.ts +4 -1
  880. package/src/hooks/useEventTheme.ts +49 -21
  881. package/src/hooks/useEvents.ts +41 -1
  882. package/src/hooks/useEvents.unit.test.ts +227 -0
  883. package/src/hooks/useFileReference.test.ts +44 -41
  884. package/src/hooks/useFileReference.ts +182 -173
  885. package/src/hooks/useFileUrl.ts +1 -1
  886. package/src/hooks/useFileUrl.unit.test.ts +684 -0
  887. package/src/hooks/useFileUrlCache.test.ts +319 -0
  888. package/src/hooks/useFileUrlCache.ts +1 -1
  889. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  890. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  891. package/src/hooks/useFormDialog.test.ts +307 -0
  892. package/src/hooks/useInactivityTracker.ts +138 -131
  893. package/src/hooks/useInactivityTracker.unit.test.ts +450 -0
  894. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  895. package/src/hooks/useIsPrint.ts +62 -0
  896. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  897. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  898. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  899. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  900. package/src/hooks/useOrganisationSecurity.ts +190 -201
  901. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  902. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  903. package/src/hooks/usePerformanceMonitor.unit.test.ts +683 -0
  904. package/src/hooks/usePermissionCache.test.ts +505 -0
  905. package/src/hooks/usePermissionCache.ts +276 -271
  906. package/src/hooks/usePreventTabReload.test.ts +307 -0
  907. package/src/hooks/usePublicEvent.simple.test.ts +779 -0
  908. package/src/hooks/usePublicEvent.test.ts +664 -0
  909. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  910. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  911. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  912. package/src/hooks/useQueryCache.test.ts +391 -0
  913. package/src/hooks/useQueryCache.ts +0 -2
  914. package/src/hooks/useRBAC.unit.test.ts +253 -0
  915. package/src/hooks/useSessionDraft.test.ts +556 -0
  916. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  917. package/src/hooks/useStorage.ts +21 -16
  918. package/src/hooks/useStorage.unit.test.ts +684 -0
  919. package/src/hooks/useToast.test.ts +413 -0
  920. package/src/hooks/useToast.unit.test.tsx +481 -0
  921. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  922. package/src/icons/index.test.ts +133 -0
  923. package/src/icons/index.ts +2 -0
  924. package/src/index.test.ts +528 -0
  925. package/src/index.ts +15 -7
  926. package/src/providers/AuthProvider.test.tsx +218 -0
  927. package/src/providers/EventProvider.test.tsx +487 -0
  928. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  929. package/src/providers/InactivityProvider.test.tsx +421 -0
  930. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  931. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  932. package/src/providers/index.test.ts +138 -0
  933. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  934. package/src/providers/services/AuthServiceProvider.test.tsx +643 -0
  935. package/src/providers/services/EventServiceProvider.test.tsx +844 -0
  936. package/src/providers/services/InactivityServiceProvider.test.tsx +667 -0
  937. package/src/providers/services/OrganisationServiceProvider.test.tsx +445 -0
  938. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  939. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  940. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  941. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  942. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  943. package/src/providers/services/contexts.test.tsx +281 -0
  944. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  945. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  946. package/src/providers/useInactivity.test-helper.ts +27 -0
  947. package/src/rbac/README.md +7 -5
  948. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  949. package/src/rbac/adapters.test.tsx +22 -22
  950. package/src/rbac/adapters.tsx +29 -29
  951. package/src/rbac/api.test.ts +1075 -87
  952. package/src/rbac/api.ts +300 -255
  953. package/src/rbac/audit-batched.test.ts +550 -0
  954. package/src/rbac/audit.ts +4 -1
  955. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  956. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  957. package/src/rbac/cache-invalidation.test.ts +715 -0
  958. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  959. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  960. package/src/rbac/components/NavigationGuard.tsx +2 -1
  961. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  962. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  963. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  964. package/src/rbac/components/PagePermissionGuard.test.tsx +1443 -0
  965. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  966. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  967. package/src/rbac/config.ts +58 -18
  968. package/src/rbac/engine.comprehensive.test.ts +808 -0
  969. package/src/rbac/engine.test.ts +494 -0
  970. package/src/rbac/engine.ts +23 -1
  971. package/src/rbac/errors.ts +89 -55
  972. package/src/rbac/hooks/permissions/runPermissionCheck.ts +91 -0
  973. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  974. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  975. package/src/rbac/hooks/permissions/useCan.test.ts +837 -0
  976. package/src/rbac/hooks/permissions/useCan.ts +177 -255
  977. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  978. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +24 -11
  979. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  980. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  981. package/src/rbac/hooks/useCan.test.ts +44 -45
  982. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  983. package/src/rbac/hooks/usePageGuardScope.ts +119 -0
  984. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  985. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  986. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  987. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  988. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  989. package/src/rbac/hooks/useRBAC.ts +145 -81
  990. package/src/rbac/hooks/useResolvedScope.ts +16 -10
  991. package/src/rbac/hooks/useResourcePermissions.test.ts +73 -83
  992. package/src/rbac/hooks/useResourcePermissions.ts +77 -152
  993. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  994. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  995. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  996. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  997. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  998. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  999. package/src/rbac/performance.test.ts +451 -0
  1000. package/src/rbac/rbac-core.test.tsx +276 -0
  1001. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  1002. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  1003. package/src/rbac/rbac-functions.test.ts +703 -0
  1004. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  1005. package/src/rbac/request-deduplication.test.ts +14 -9
  1006. package/src/rbac/request-deduplication.ts +5 -4
  1007. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  1008. package/src/rbac/secureClient.test.ts +514 -83
  1009. package/src/rbac/secureClient.ts +8 -2
  1010. package/src/rbac/security.test.ts +323 -0
  1011. package/src/rbac/types/roleManagement.ts +66 -0
  1012. package/src/rbac/types.ts +3 -0
  1013. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  1014. package/src/rbac/utils/contextValidator.test.ts +126 -0
  1015. package/src/rbac/utils/contextValidator.ts +5 -1
  1016. package/src/rbac/utils/deep-equal.test.ts +76 -0
  1017. package/src/rbac/utils/eventContext.test.ts +401 -0
  1018. package/src/rbac/utils/eventContext.ts +37 -33
  1019. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  1020. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  1021. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  1022. package/src/services/AuthService.edge-cases.test.ts +746 -0
  1023. package/src/services/AuthService.restoreSession.test.ts +59 -0
  1024. package/src/services/AuthService.test.ts +1362 -0
  1025. package/src/services/AuthService.ts +184 -205
  1026. package/src/services/BaseService.edge-cases.test.ts +506 -0
  1027. package/src/services/BaseService.test.ts +363 -0
  1028. package/src/services/EventService.edge-cases.test.ts +636 -0
  1029. package/src/services/EventService.eventColours.test.ts +64 -0
  1030. package/src/services/EventService.test.ts +1250 -0
  1031. package/src/services/EventService.ts +251 -316
  1032. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  1033. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  1034. package/src/services/InactivityService.test.ts +829 -0
  1035. package/src/services/InactivityService.ts +172 -213
  1036. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  1037. package/src/services/OrganisationService.pagination.test.ts +409 -0
  1038. package/src/services/OrganisationService.test.ts +1579 -0
  1039. package/src/services/OrganisationService.ts +184 -238
  1040. package/src/services/base/BaseService.test.ts +1 -1
  1041. package/src/services/interfaces/IAuthService.test.ts +184 -0
  1042. package/src/services/interfaces/IAuthService.ts +10 -9
  1043. package/src/services/interfaces/IEventService.test.ts +176 -0
  1044. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  1045. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  1046. package/src/styles/core.css +243 -12
  1047. package/src/theming/parseEventColours.test.ts +321 -0
  1048. package/src/theming/runtime.test.ts +495 -0
  1049. package/src/theming/runtime.ts +71 -2
  1050. package/src/types/api-result.ts +53 -0
  1051. package/src/types/core.test.ts +397 -0
  1052. package/src/types/database-generated.test.ts +78 -0
  1053. package/src/types/database.generated.ts +45 -10
  1054. package/src/types/event.ts +38 -18
  1055. package/src/types/file-reference.test.ts +351 -0
  1056. package/src/types/file-reference.ts +37 -12
  1057. package/src/types/guards.test.ts +246 -0
  1058. package/src/types/index.test.ts +265 -0
  1059. package/src/types/index.ts +3 -0
  1060. package/src/types/organisation.roles.test.ts +55 -0
  1061. package/src/types/organisation.test.ts +1105 -0
  1062. package/src/types/organisation.ts +15 -15
  1063. package/src/types/supabase.ts +13 -4
  1064. package/src/types/theme.test.ts +830 -0
  1065. package/src/types/type-validation.test.ts +526 -0
  1066. package/src/types/validation.test.ts +729 -0
  1067. package/src/utils/app/appIdResolver.test.ts +98 -71
  1068. package/src/utils/app/appIdResolver.ts +31 -20
  1069. package/src/utils/appConfig.unit.test.ts +55 -0
  1070. package/src/utils/audit.unit.test.ts +69 -0
  1071. package/src/utils/auth-utils.unit.test.ts +69 -0
  1072. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  1073. package/src/utils/cn.unit.test.ts +34 -0
  1074. package/src/utils/context/organisationContext.test.ts +105 -91
  1075. package/src/utils/context/organisationContext.ts +29 -40
  1076. package/src/utils/core/cn.test.ts +66 -0
  1077. package/src/utils/core/debugLogger.test.ts +113 -0
  1078. package/src/utils/core/logger.test.ts +217 -0
  1079. package/src/utils/core/mergeRefs.ts +24 -0
  1080. package/src/utils/debugLogger.test.ts +417 -0
  1081. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  1082. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  1083. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  1084. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  1085. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  1086. package/src/utils/file-reference/file-reference.test.ts +1249 -0
  1087. package/src/utils/file-reference/index.ts +330 -347
  1088. package/src/utils/formatDate.unit.test.ts +109 -0
  1089. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  1090. package/src/utils/formatting/formatNumber.test.ts +1 -1
  1091. package/src/utils/formatting.unit.test.ts +99 -0
  1092. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  1093. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  1094. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  1095. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  1096. package/src/utils/index.unit.test.ts +251 -0
  1097. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  1098. package/src/utils/location/location.test.ts +1 -1
  1099. package/src/utils/logger.unit.test.ts +398 -0
  1100. package/src/utils/organisationContext.unit.test.ts +180 -0
  1101. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  1102. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  1103. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  1104. package/src/utils/performanceBenchmark.test.ts +174 -0
  1105. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  1106. package/src/utils/permissionTypes.unit.test.ts +250 -0
  1107. package/src/utils/permissionUtils.unit.test.ts +362 -0
  1108. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  1109. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  1110. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  1111. package/src/utils/request-deduplication.test.ts +349 -0
  1112. package/src/utils/sanitization.unit.test.ts +346 -0
  1113. package/src/utils/schemaUtils.unit.test.ts +441 -0
  1114. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  1115. package/src/utils/secureErrors.unit.test.ts +390 -0
  1116. package/src/utils/secureStorage.unit.test.ts +289 -0
  1117. package/src/utils/security/auth-utils.ts +34 -23
  1118. package/src/utils/security/secureDataAccess.ts +241 -281
  1119. package/src/utils/security/secureErrors.test.ts +1 -1
  1120. package/src/utils/security/secureStorage.test.ts +1 -1
  1121. package/src/utils/security/security.test.ts +25 -17
  1122. package/src/utils/security/security.ts +15 -18
  1123. package/src/utils/security/securityMonitor.test.ts +1 -1
  1124. package/src/utils/security.unit.test.ts +155 -0
  1125. package/src/utils/securityMonitor.unit.test.ts +276 -0
  1126. package/src/utils/sessionTracking.unit.test.ts +218 -0
  1127. package/src/utils/storage/config.unit.test.ts +239 -0
  1128. package/src/utils/storage/helpers.test.ts +88 -102
  1129. package/src/utils/storage/helpers.ts +173 -251
  1130. package/src/utils/storage/index.unit.test.ts +68 -0
  1131. package/src/utils/storage/types.ts +7 -0
  1132. package/src/utils/supabase/createBaseClient.test.ts +31 -14
  1133. package/src/utils/timezone/timezone.test.ts +1 -1
  1134. package/src/utils/timezone.test.ts +345 -0
  1135. package/src/utils/validation/common.test.ts +115 -0
  1136. package/src/utils/validation/csrf.test.ts +198 -0
  1137. package/src/utils/validation/csrf.ts +42 -41
  1138. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  1139. package/src/utils/validation/passwordSchema.test.ts +164 -0
  1140. package/src/utils/validation/schema.test.ts +127 -0
  1141. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  1142. package/src/utils/validation/user.test.ts +173 -0
  1143. package/src/utils/validation/validation.test.ts +197 -0
  1144. package/src/utils/validation/validationUtils.test.ts +294 -0
  1145. package/src/utils/validation.unit.test.ts +307 -0
  1146. package/src/utils/validationUtils.unit.test.ts +558 -0
  1147. package/dist/DataTable-SAXFG4XI.js +0 -13
  1148. package/dist/InactivityServiceProvider-DHryoh6K.d.ts +0 -299
  1149. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  1150. package/dist/UnifiedAuthProvider-CiBAl9-s.d.ts +0 -151
  1151. package/dist/api-F47QJ7FX.js +0 -4
  1152. package/dist/audit-Z6ZZBWLU.js +0 -3
  1153. package/dist/auth-BZOJqrdd.d.ts +0 -49
  1154. package/dist/chunk-3GWSPISD.js +0 -61
  1155. package/dist/chunk-66R6RLUZ.js +0 -529
  1156. package/dist/chunk-7YDC7LMU.js +0 -487
  1157. package/dist/chunk-BCTXBU6U.js +0 -704
  1158. package/dist/chunk-FBZ7U3ID.js +0 -2209
  1159. package/dist/chunk-FN52B75D.js +0 -246
  1160. package/dist/chunk-JJEYZ3DX.js +0 -165
  1161. package/dist/chunk-KPYQWGFQ.js +0 -183
  1162. package/dist/chunk-KSNLMI7N.js +0 -481
  1163. package/dist/chunk-KYURMOQM.js +0 -977
  1164. package/dist/chunk-LNHFAF4X.js +0 -2279
  1165. package/dist/chunk-MPY44PWB.js +0 -8510
  1166. package/dist/chunk-NIU6DPQV.js +0 -427
  1167. package/dist/chunk-TFIPNIPE.js +0 -5379
  1168. package/dist/chunk-UZNAFKGW.js +0 -125
  1169. package/dist/chunk-W46INAVW.js +0 -1216
  1170. package/dist/chunk-X5EAU5G7.js +0 -793
  1171. package/dist/chunk-Y4PF6HIM.js +0 -2862
  1172. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  1173. package/dist/event-WTAQuGcq.d.ts +0 -239
  1174. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  1175. package/dist/functions-DH45k8ec.d.ts +0 -208
  1176. package/dist/timezone-K-ptz3HO.d.ts +0 -696
  1177. package/dist/types-BE2sEHKd.d.ts +0 -55
  1178. package/dist/types-CvOPXWWZ.d.ts +0 -111
  1179. package/dist/types-D05dCGma.d.ts +0 -521
  1180. package/dist/usePublicPageContext-vxBlEHO9.d.ts +0 -4290
  1181. package/dist/usePublicRouteParams-G3Ks53mk.d.ts +0 -877
  1182. package/docs/api/modules.md +0 -9889
  1183. package/scripts/build-docs-incremental.js +0 -179
  1184. package/scripts/eslint-audit.cjs +0 -222
  1185. package/scripts/generate-docs.js +0 -157
  1186. package/scripts/install-cursor-rules.cjs +0 -255
  1187. package/scripts/install-eslint-config.cjs +0 -349
  1188. package/scripts/setup-build-cache.js +0 -73
  1189. package/scripts/validate-pre-publish.js +0 -145
  1190. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  1191. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  1192. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  1193. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  1194. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -446
  1195. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  1196. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  1197. package/src/__tests__/index.test.ts +0 -532
  1198. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  1199. package/src/__tests__/public-recipe-view.test.ts +0 -228
  1200. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -222
  1201. package/src/__tests__/rls-policies.test.ts +0 -472
  1202. package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +0 -360
  1203. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  1204. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  1205. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  1206. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  1207. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  1208. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -485
  1209. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  1210. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  1211. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -970
  1212. package/src/components/DataTable/__tests__/README.md +0 -145
  1213. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  1214. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  1215. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  1216. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -728
  1217. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -319
  1218. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  1219. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  1220. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -388
  1221. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  1222. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  1223. package/src/components/DataTable/components/ActionButtons.tsx +0 -195
  1224. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  1225. package/src/components/DataTable/components/ColumnFilter.tsx +0 -113
  1226. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  1227. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  1228. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  1229. package/src/components/DataTable/components/DataTableModals.tsx +0 -333
  1230. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  1231. package/src/components/DataTable/components/EditFields.tsx +0 -286
  1232. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  1233. package/src/components/DataTable/components/EmptyState.tsx +0 -82
  1234. package/src/components/DataTable/components/FilterRow.tsx +0 -148
  1235. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  1236. package/src/components/DataTable/components/PaginationControls.tsx +0 -285
  1237. package/src/components/DataTable/components/RowComponent.tsx +0 -423
  1238. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  1239. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  1240. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -245
  1241. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -919
  1242. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -544
  1243. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -484
  1244. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -748
  1245. package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +0 -792
  1246. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -438
  1247. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  1248. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  1249. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -629
  1250. package/src/components/DataTable/components/__tests__/EditFields.test.tsx +0 -526
  1251. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -994
  1252. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -420
  1253. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -415
  1254. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -612
  1255. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  1256. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -81
  1257. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -429
  1258. package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +0 -629
  1259. package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +0 -135
  1260. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -864
  1261. package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +0 -453
  1262. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  1263. package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +0 -184
  1264. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  1265. package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +0 -381
  1266. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  1267. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -328
  1268. package/src/components/DataTable/core/ActionManager.ts +0 -235
  1269. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  1270. package/src/components/DataTable/core/DataManager.ts +0 -190
  1271. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  1272. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  1273. package/src/components/DataTable/core/StateManager.ts +0 -312
  1274. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  1275. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -403
  1276. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  1277. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  1278. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  1279. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  1280. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  1281. package/src/components/DataTable/core/interfaces.ts +0 -338
  1282. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -516
  1283. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -256
  1284. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -297
  1285. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -270
  1286. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -280
  1287. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -691
  1288. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -183
  1289. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -294
  1290. package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +0 -787
  1291. package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +0 -258
  1292. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -499
  1293. package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +0 -440
  1294. package/src/components/DataTable/types.ts +0 -764
  1295. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -548
  1296. package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +0 -288
  1297. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1298. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -209
  1299. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1300. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1301. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -235
  1302. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -586
  1303. package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +0 -593
  1304. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1305. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -235
  1306. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -208
  1307. package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +0 -1934
  1308. package/src/components/Select/__tests__/context.test.tsx +0 -56
  1309. package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +0 -279
  1310. package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +0 -295
  1311. package/src/components/Select/hooks/__tests__/useSelectState.test.ts +0 -254
  1312. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1313. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1314. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1315. package/src/components/Select/utils/__tests__/text.test.tsx +0 -104
  1316. package/src/components/Select/utils/text.ts +0 -26
  1317. package/src/components/__tests__/index.test.ts +0 -346
  1318. package/src/constants/__tests__/performance.test.ts +0 -91
  1319. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -725
  1320. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -608
  1321. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1322. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -406
  1323. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -328
  1324. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -720
  1325. package/src/hooks/__tests__/useDataTableState.test.ts +0 -170
  1326. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -157
  1327. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -227
  1328. package/src/hooks/__tests__/useFileDisplay.test.ts +0 -540
  1329. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1109
  1330. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -696
  1331. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -319
  1332. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -604
  1333. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -613
  1334. package/src/hooks/__tests__/useFormDialog.test.ts +0 -307
  1335. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1336. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1337. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -907
  1338. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -293
  1339. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1340. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1341. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1342. package/src/hooks/__tests__/usePermissionCache.test.ts +0 -506
  1343. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -307
  1344. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -794
  1345. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -670
  1346. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -638
  1347. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -948
  1348. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -442
  1349. package/src/hooks/__tests__/useQueryCache.test.ts +0 -391
  1350. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1351. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -556
  1352. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1353. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -721
  1354. package/src/hooks/__tests__/useToast.test.ts +0 -413
  1355. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1356. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -191
  1357. package/src/hooks/public/usePublicFileDisplay.test.ts +0 -723
  1358. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  1359. package/src/hooks/useFileDisplay.ts +0 -748
  1360. package/src/icons/__tests__/index.test.ts +0 -133
  1361. package/src/providers/OrganisationProvider.test.tsx +0 -40
  1362. package/src/providers/OrganisationProvider.tsx +0 -92
  1363. package/src/providers/__tests__/AuthProvider.test.tsx +0 -218
  1364. package/src/providers/__tests__/EventProvider.test.tsx +0 -487
  1365. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1366. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -428
  1367. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  1368. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  1369. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -308
  1370. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -503
  1371. package/src/providers/__tests__/index.test.ts +0 -138
  1372. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -229
  1373. package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +0 -638
  1374. package/src/providers/services/__tests__/EventServiceProvider.test.tsx +0 -839
  1375. package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +0 -662
  1376. package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +0 -440
  1377. package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +0 -435
  1378. package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +0 -408
  1379. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -301
  1380. package/src/providers/services/__tests__/contexts.test.tsx +0 -281
  1381. package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +0 -251
  1382. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -429
  1383. package/src/rbac/__tests__/audit-batched.test.ts +0 -550
  1384. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -300
  1385. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -517
  1386. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  1387. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -808
  1388. package/src/rbac/__tests__/performance.test.ts +0 -451
  1389. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1390. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -387
  1391. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -252
  1392. package/src/rbac/__tests__/rbac-functions.test.ts +0 -646
  1393. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1394. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -271
  1395. package/src/rbac/components/__tests__/AccessDenied.test.tsx +0 -324
  1396. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -1146
  1397. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -231
  1398. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -243
  1399. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1430
  1400. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -185
  1401. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -427
  1402. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -1179
  1403. package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +0 -622
  1404. package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +0 -798
  1405. package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +0 -843
  1406. package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +0 -545
  1407. package/src/rbac/utils/__tests__/clientSecurity.test.ts +0 -192
  1408. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -126
  1409. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -76
  1410. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -386
  1411. package/src/services/__tests__/AuthService.edge-cases.test.ts +0 -746
  1412. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -59
  1413. package/src/services/__tests__/AuthService.test.ts +0 -1328
  1414. package/src/services/__tests__/BaseService.edge-cases.test.ts +0 -506
  1415. package/src/services/__tests__/BaseService.test.ts +0 -363
  1416. package/src/services/__tests__/EventService.edge-cases.test.ts +0 -633
  1417. package/src/services/__tests__/EventService.eventColours.test.ts +0 -64
  1418. package/src/services/__tests__/EventService.test.ts +0 -1018
  1419. package/src/services/__tests__/InactivityService.edge-cases.test.ts +0 -492
  1420. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -406
  1421. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1422. package/src/services/__tests__/OrganisationService.edge-cases.test.ts +0 -633
  1423. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1424. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1425. package/src/services/interfaces/__tests__/IAuthService.test.ts +0 -190
  1426. package/src/services/interfaces/__tests__/IEventService.test.ts +0 -176
  1427. package/src/services/interfaces/__tests__/IInactivityService.test.ts +0 -183
  1428. package/src/services/interfaces/__tests__/IOrganisationService.test.ts +0 -207
  1429. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1430. package/src/theming/__tests__/runtime.test.ts +0 -504
  1431. package/src/types/__tests__/core.test.ts +0 -397
  1432. package/src/types/__tests__/database-generated.test.ts +0 -78
  1433. package/src/types/__tests__/file-reference.test.ts +0 -351
  1434. package/src/types/__tests__/guards.test.ts +0 -246
  1435. package/src/types/__tests__/index.test.ts +0 -265
  1436. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1437. package/src/types/__tests__/organisation.test.ts +0 -1133
  1438. package/src/types/__tests__/theme.test.ts +0 -830
  1439. package/src/types/__tests__/type-validation.test.ts +0 -526
  1440. package/src/types/__tests__/validation.test.ts +0 -729
  1441. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1442. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1443. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1444. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -326
  1445. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1446. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1447. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1448. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -331
  1449. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1450. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1451. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1452. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -320
  1453. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1454. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1455. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -174
  1456. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -288
  1457. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1458. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1459. package/src/utils/__tests__/request-deduplication.test.ts +0 -349
  1460. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1461. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1462. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -334
  1463. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1464. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1465. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1466. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1467. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1468. package/src/utils/__tests__/timezone.test.ts +0 -345
  1469. package/src/utils/__tests__/validation.unit.test.ts +0 -307
  1470. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1471. package/src/utils/core/__tests__/cn.test.ts +0 -66
  1472. package/src/utils/core/__tests__/debugLogger.test.ts +0 -113
  1473. package/src/utils/core/__tests__/logger.test.ts +0 -217
  1474. package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +0 -185
  1475. package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +0 -156
  1476. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -1313
  1477. package/src/utils/performance/__tests__/bundleAnalysis.test.ts +0 -148
  1478. package/src/utils/performance/__tests__/performanceBenchmark.test.ts +0 -251
  1479. package/src/utils/performance/__tests__/performanceBudgets.test.ts +0 -241
  1480. package/src/utils/permissions/__tests__/permissionTypes.test.ts +0 -149
  1481. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -306
  1482. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -271
  1483. package/src/utils/storage/__tests__/config.unit.test.ts +0 -239
  1484. package/src/utils/storage/__tests__/index.unit.test.ts +0 -68
  1485. package/src/utils/validation/__tests__/common.test.ts +0 -115
  1486. package/src/utils/validation/__tests__/csrf.test.ts +0 -170
  1487. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -618
  1488. package/src/utils/validation/__tests__/passwordSchema.test.ts +0 -164
  1489. package/src/utils/validation/__tests__/schema.test.ts +0 -127
  1490. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -165
  1491. package/src/utils/validation/__tests__/user.test.ts +0 -173
  1492. package/src/utils/validation/__tests__/validation.test.ts +0 -197
  1493. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -294
  1494. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1495. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1496. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  1497. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1498. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  1499. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  1500. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -0,0 +1,2159 @@
1
+ import { EventServiceContext } from './chunk-S57OLCLO.js';
2
+ import { clearPalette, parseAndNormalizeEventColours, applyPalette } from './chunk-D6BMFMQZ.js';
3
+ import { assertAppId } from './chunk-4SXLQIZO.js';
4
+ import { fetchPlaceDetails, createAddressFromPlaceResult, getAddressByPlaceId, fetchPlaceAutocomplete, setOrganisationContext } from './chunk-XPFVT3GN.js';
5
+ import { createLogger, logger } from './chunk-BTHN5MKC.js';
6
+ import { ok, err } from './chunk-44CNXN4P.js';
7
+ import { useState, useEffect, useCallback, useMemo, useRef, useContext } from 'react';
8
+ import { useLocation } from 'react-router-dom';
9
+
10
+ function useDebounce(value, delay) {
11
+ const [debouncedValue, setDebouncedValue] = useState(value);
12
+ useEffect(() => {
13
+ const handler = setTimeout(() => {
14
+ setDebouncedValue(value);
15
+ }, delay);
16
+ return () => {
17
+ clearTimeout(handler);
18
+ };
19
+ }, [value, delay]);
20
+ return debouncedValue;
21
+ }
22
+ var log = createLogger("useQueryCache");
23
+ var queryCache = /* @__PURE__ */ new Map();
24
+ var CLEANUP_INTERVAL_MS = 5 * 60 * 1e3;
25
+ var cleanupTimer = null;
26
+ function runCacheCleanup() {
27
+ const now = Date.now();
28
+ const expiredKeys = [];
29
+ queryCache.forEach((entry, key) => {
30
+ if (entry.expiresAt <= now) {
31
+ expiredKeys.push(key);
32
+ }
33
+ });
34
+ expiredKeys.forEach((key) => {
35
+ queryCache.delete(key);
36
+ log.debug(`Removed expired query from cache: ${key}`);
37
+ });
38
+ }
39
+ if (typeof window !== "undefined" && !cleanupTimer) {
40
+ cleanupTimer = setInterval(runCacheCleanup, CLEANUP_INTERVAL_MS);
41
+ window.addEventListener("beforeunload", () => {
42
+ if (cleanupTimer) {
43
+ clearInterval(cleanupTimer);
44
+ cleanupTimer = null;
45
+ }
46
+ });
47
+ }
48
+ function cleanupQueryCache() {
49
+ if (cleanupTimer) {
50
+ clearInterval(cleanupTimer);
51
+ cleanupTimer = null;
52
+ }
53
+ }
54
+ function useQueryCache(_supabase) {
55
+ const getCachedQuery = useCallback(async (table, filterKey, filterValue, fetchFn, options = {}) => {
56
+ const { ttl = 300, enabled = true } = options;
57
+ const cacheKey = `${table}:${filterKey}:${filterValue}`;
58
+ const now = Date.now();
59
+ if (!enabled) {
60
+ return fetchFn();
61
+ }
62
+ const cached = queryCache.get(cacheKey);
63
+ if (cached) {
64
+ if (cached.expiresAt > now && cached.data !== void 0) {
65
+ log.debug(`Cache hit for query: ${cacheKey}`);
66
+ return cached.data;
67
+ }
68
+ if (cached.promise) {
69
+ log.debug(`Waiting for in-flight request: ${cacheKey}`);
70
+ return cached.promise;
71
+ }
72
+ }
73
+ log.debug(`Cache miss for query: ${cacheKey}, fetching...`);
74
+ const fetchPromise = fetchFn();
75
+ queryCache.set(cacheKey, {
76
+ data: void 0,
77
+ expiresAt: now + ttl * 1e3,
78
+ promise: fetchPromise
79
+ });
80
+ try {
81
+ const data = await fetchPromise;
82
+ queryCache.set(cacheKey, {
83
+ data,
84
+ expiresAt: now + ttl * 1e3
85
+ });
86
+ log.debug(`Cached query result: ${cacheKey}, expires in ${ttl}s`);
87
+ return data;
88
+ } catch (error) {
89
+ queryCache.delete(cacheKey);
90
+ log.error(`Query failed for ${cacheKey}:`, error);
91
+ throw error;
92
+ }
93
+ }, []);
94
+ const invalidateQuery = useCallback((table, filterKey, filterValue) => {
95
+ const cacheKey = `${table}:${filterKey}:${filterValue}`;
96
+ queryCache.delete(cacheKey);
97
+ log.debug(`Invalidated query cache: ${cacheKey}`);
98
+ }, []);
99
+ const clearCache = useCallback(() => {
100
+ queryCache.clear();
101
+ log.debug("Cleared all query cache entries.");
102
+ }, []);
103
+ const getCacheStats = useCallback(() => {
104
+ return {
105
+ size: queryCache.size,
106
+ keys: Array.from(queryCache.keys())
107
+ };
108
+ }, []);
109
+ return {
110
+ getCachedQuery,
111
+ invalidateQuery,
112
+ clearCache,
113
+ getCacheStats
114
+ };
115
+ }
116
+ var queryCacheHelpers = {
117
+ /**
118
+ * Cache core_person queries by user_id
119
+ * TTL: 5 minutes
120
+ */
121
+ pacePersonByUserId: (supabase, userId, fetchFn) => {
122
+ const cacheKey = `core_person:user_id:${userId}`;
123
+ const now = Date.now();
124
+ const ttl = 300 * 1e3;
125
+ const cached = queryCache.get(cacheKey);
126
+ if (cached && cached.expiresAt > now && cached.data !== void 0) {
127
+ return Promise.resolve(cached.data);
128
+ }
129
+ if (cached?.promise) {
130
+ return cached.promise;
131
+ }
132
+ const promise = fetchFn();
133
+ queryCache.set(cacheKey, {
134
+ data: void 0,
135
+ expiresAt: now + ttl,
136
+ promise
137
+ });
138
+ promise.then((data) => {
139
+ queryCache.set(cacheKey, { data, expiresAt: now + ttl });
140
+ }).catch(() => {
141
+ queryCache.delete(cacheKey);
142
+ });
143
+ return promise;
144
+ },
145
+ /**
146
+ * Cache core_member queries by person_id
147
+ * TTL: 5 minutes
148
+ */
149
+ paceMemberByPersonId: (supabase, personId, fetchFn) => {
150
+ const cacheKey = `core_member:person_id:${personId}`;
151
+ const now = Date.now();
152
+ const ttl = 300 * 1e3;
153
+ const cached = queryCache.get(cacheKey);
154
+ if (cached && cached.expiresAt > now && cached.data !== void 0) {
155
+ return Promise.resolve(cached.data);
156
+ }
157
+ if (cached?.promise) {
158
+ return cached.promise;
159
+ }
160
+ const promise = fetchFn();
161
+ queryCache.set(cacheKey, {
162
+ data: void 0,
163
+ expiresAt: now + ttl,
164
+ promise
165
+ });
166
+ promise.then((data) => {
167
+ queryCache.set(cacheKey, { data, expiresAt: now + ttl });
168
+ }).catch(() => {
169
+ queryCache.delete(cacheKey);
170
+ });
171
+ return promise;
172
+ },
173
+ /**
174
+ * Cache rbac_app_pages queries by app_id
175
+ * TTL: 15 minutes (app pages are relatively static)
176
+ */
177
+ rbacAppPagesByAppId: (supabase, appId, fetchFn) => {
178
+ const cacheKey = `rbac_app_pages:app_id:${appId}`;
179
+ const now = Date.now();
180
+ const ttl = 15 * 60 * 1e3;
181
+ const cached = queryCache.get(cacheKey);
182
+ if (cached && cached.expiresAt > now && cached.data !== void 0) {
183
+ return Promise.resolve(cached.data);
184
+ }
185
+ if (cached?.promise) {
186
+ return cached.promise;
187
+ }
188
+ const promise = fetchFn();
189
+ queryCache.set(cacheKey, {
190
+ data: void 0,
191
+ expiresAt: now + ttl,
192
+ promise
193
+ });
194
+ promise.then((data) => {
195
+ queryCache.set(cacheKey, { data, expiresAt: now + ttl });
196
+ }).catch(() => {
197
+ queryCache.delete(cacheKey);
198
+ });
199
+ return promise;
200
+ }
201
+ };
202
+ async function fetchSuggestionsForInput(debouncedInput, apiKey, memoizedAutocompleteOptions, cacheEnabled, cacheTTLAutocomplete, getCachedQuery, isCancelledRef, setters) {
203
+ try {
204
+ let result;
205
+ if (cacheEnabled) {
206
+ result = await getCachedQuery(
207
+ "google-places-autocomplete",
208
+ "query",
209
+ debouncedInput,
210
+ async () => {
211
+ if (isCancelledRef.current) {
212
+ throw new Error("Request cancelled");
213
+ }
214
+ return fetchPlaceAutocomplete(debouncedInput, apiKey, memoizedAutocompleteOptions);
215
+ },
216
+ { ttl: cacheTTLAutocomplete, enabled: true }
217
+ );
218
+ } else {
219
+ result = await fetchPlaceAutocomplete(debouncedInput, apiKey, memoizedAutocompleteOptions);
220
+ }
221
+ if (isCancelledRef.current) return;
222
+ if (!result.ok) {
223
+ setters.setError(new Error(result.error.message));
224
+ setters.setSuggestions([]);
225
+ setters.setIsLoading(false);
226
+ return;
227
+ }
228
+ setters.setSuggestions(result.data);
229
+ setters.setIsLoading(false);
230
+ } catch (err2) {
231
+ if (isCancelledRef.current || err2 instanceof Error && err2.message === "Request cancelled") {
232
+ return;
233
+ }
234
+ const error = err2 instanceof Error ? err2 : new Error("Failed to fetch autocomplete suggestions");
235
+ setters.setError(error);
236
+ setters.setSuggestions([]);
237
+ setters.setIsLoading(false);
238
+ }
239
+ }
240
+ function useAddressAutocomplete(apiKey, inputValue, options = {}) {
241
+ const {
242
+ debounceDelay = 300,
243
+ cacheEnabled = true,
244
+ cacheTTL = {
245
+ autocomplete: 3600,
246
+ // 1 hour
247
+ placeDetails: 86400
248
+ // 24 hours
249
+ },
250
+ autocompleteOptions
251
+ } = options;
252
+ const [suggestions, setSuggestions] = useState([]);
253
+ const [isLoading, setIsLoading] = useState(false);
254
+ const [error, setError] = useState(null);
255
+ const debouncedInput = useDebounce(inputValue, debounceDelay);
256
+ const { getCachedQuery } = useQueryCache();
257
+ const memoizedAutocompleteOptions = useMemo(() => {
258
+ if (!autocompleteOptions) {
259
+ return void 0;
260
+ }
261
+ return {
262
+ components: autocompleteOptions.components,
263
+ location: autocompleteOptions.location,
264
+ radius: autocompleteOptions.radius,
265
+ language: autocompleteOptions.language,
266
+ types: autocompleteOptions.types
267
+ };
268
+ }, [
269
+ autocompleteOptions
270
+ ]);
271
+ useEffect(() => {
272
+ if (!debouncedInput.trim()) {
273
+ setSuggestions([]);
274
+ setIsLoading(false);
275
+ setError(null);
276
+ return;
277
+ }
278
+ if (!apiKey) {
279
+ setError(new Error("Google Places API key is required"));
280
+ return;
281
+ }
282
+ setIsLoading(true);
283
+ setError(null);
284
+ const isCancelledRef = { current: false };
285
+ fetchSuggestionsForInput(
286
+ debouncedInput,
287
+ apiKey,
288
+ memoizedAutocompleteOptions,
289
+ cacheEnabled,
290
+ cacheTTL.autocomplete ?? 3600,
291
+ getCachedQuery,
292
+ isCancelledRef,
293
+ { setSuggestions, setError, setIsLoading }
294
+ );
295
+ return () => {
296
+ isCancelledRef.current = true;
297
+ };
298
+ }, [debouncedInput, apiKey, cacheEnabled, cacheTTL.autocomplete, memoizedAutocompleteOptions, getCachedQuery]);
299
+ const selectAddress = useCallback(
300
+ async (placeId) => {
301
+ if (!placeId || !apiKey) {
302
+ return null;
303
+ }
304
+ setIsLoading(true);
305
+ setError(null);
306
+ try {
307
+ let placeResult;
308
+ if (cacheEnabled) {
309
+ placeResult = await getCachedQuery(
310
+ "google-places-details",
311
+ "place_id",
312
+ placeId,
313
+ async () => fetchPlaceDetails(placeId, apiKey),
314
+ { ttl: cacheTTL.placeDetails, enabled: true }
315
+ );
316
+ } else {
317
+ placeResult = await fetchPlaceDetails(placeId, apiKey);
318
+ }
319
+ if (!placeResult.ok) {
320
+ setError(new Error(placeResult.error.message));
321
+ setIsLoading(false);
322
+ return null;
323
+ }
324
+ const parsedAddress = createAddressFromPlaceResult(placeResult.data);
325
+ setIsLoading(false);
326
+ return parsedAddress;
327
+ } catch (err2) {
328
+ const error2 = err2 instanceof Error ? err2 : new Error("Failed to fetch place details");
329
+ setError(error2);
330
+ setIsLoading(false);
331
+ return null;
332
+ }
333
+ },
334
+ // eslint-disable-next-line react-hooks/exhaustive-deps
335
+ [apiKey, cacheEnabled, cacheTTL.placeDetails]
336
+ );
337
+ const getAddressByPlaceIdFn = useCallback(
338
+ async (placeId) => {
339
+ if (!placeId || !apiKey) {
340
+ return null;
341
+ }
342
+ try {
343
+ let result;
344
+ if (cacheEnabled) {
345
+ result = await getCachedQuery(
346
+ "google-places-details",
347
+ "place_id",
348
+ placeId,
349
+ async () => getAddressByPlaceId(placeId, apiKey),
350
+ { ttl: cacheTTL.placeDetails, enabled: true }
351
+ );
352
+ } else {
353
+ result = await getAddressByPlaceId(placeId, apiKey);
354
+ }
355
+ if (!result.ok) {
356
+ setError(new Error(result.error.message));
357
+ return null;
358
+ }
359
+ return result.data;
360
+ } catch (err2) {
361
+ const error2 = err2 instanceof Error ? err2 : new Error("Failed to get address by place_id");
362
+ setError(error2);
363
+ return null;
364
+ }
365
+ },
366
+ // eslint-disable-next-line react-hooks/exhaustive-deps
367
+ [apiKey, cacheEnabled, cacheTTL.placeDetails]
368
+ );
369
+ const clearSuggestions = useCallback(() => {
370
+ setSuggestions([]);
371
+ setError(null);
372
+ }, []);
373
+ return {
374
+ suggestions,
375
+ isLoading,
376
+ error,
377
+ selectAddress,
378
+ getAddressByPlaceId: getAddressByPlaceIdFn,
379
+ clearSuggestions
380
+ };
381
+ }
382
+
383
+ // src/utils/storage/config.ts
384
+ var FILE_SIZE_LIMITS = {
385
+ // Images
386
+ "image/jpeg": 5 * 1024 * 1024,
387
+ // 5MB
388
+ "image/png": 5 * 1024 * 1024,
389
+ // 5MB
390
+ "image/gif": 10 * 1024 * 1024,
391
+ // 10MB (for animations)
392
+ "image/webp": 5 * 1024 * 1024,
393
+ // 5MB
394
+ "image/svg+xml": 1 * 1024 * 1024,
395
+ // 1MB (vector graphics)
396
+ // Documents
397
+ "application/pdf": 50 * 1024 * 1024,
398
+ // 50MB
399
+ "application/msword": 25 * 1024 * 1024,
400
+ // 25MB
401
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": 25 * 1024 * 1024,
402
+ // 25MB
403
+ "application/vnd.ms-excel": 25 * 1024 * 1024,
404
+ // 25MB
405
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": 25 * 1024 * 1024,
406
+ // 25MB
407
+ // Archives
408
+ "application/zip": 100 * 1024 * 1024,
409
+ // 100MB
410
+ "application/x-rar-compressed": 100 * 1024 * 1024,
411
+ // 100MB
412
+ // Text files
413
+ "text/plain": 1 * 1024 * 1024,
414
+ // 1MB
415
+ "text/csv": 10 * 1024 * 1024,
416
+ // 10MB
417
+ "application/json": 10 * 1024 * 1024
418
+ // 10MB
419
+ };
420
+ var DEFAULT_FILE_SIZE_LIMIT = 10 * 1024 * 1024;
421
+ var APP_PATH_MAPPING = {
422
+ "PACE": "event_logos",
423
+ "TRAC": "trac_accommodation",
424
+ // Default category for TRAC files
425
+ "MEDI": "documents",
426
+ "CAKE": "documents"
427
+ };
428
+ var STORAGE_CONFIG = {
429
+ bucketName: "files",
430
+ fileSizeLimits: FILE_SIZE_LIMITS,
431
+ defaultFileSizeLimit: DEFAULT_FILE_SIZE_LIMIT
432
+ };
433
+ function getFileSizeLimit(mimeType) {
434
+ return STORAGE_CONFIG.fileSizeLimits[mimeType] || STORAGE_CONFIG.defaultFileSizeLimit;
435
+ }
436
+ function getBucketName(isPublic) {
437
+ return isPublic ? "public-files" : "files";
438
+ }
439
+ function validateFileSize(file) {
440
+ const limit = getFileSizeLimit(file.type);
441
+ if (file.size > limit) {
442
+ const limitMB = Math.round(limit / (1024 * 1024));
443
+ const fileMB = Math.round(file.size / (1024 * 1024));
444
+ return {
445
+ isValid: false,
446
+ error: `File size (${fileMB}MB) exceeds limit (${limitMB}MB) for ${file.type}`
447
+ };
448
+ }
449
+ return { isValid: true };
450
+ }
451
+
452
+ // src/utils/storage/helpers.ts
453
+ var log2 = createLogger("StorageHelpers");
454
+ function generateFilePath(options, fileName) {
455
+ const { orgId, userId, isPublic = false, customPath } = options;
456
+ if (!orgId && !userId) {
457
+ throw new Error("Either orgId or userId is required for file path generation");
458
+ }
459
+ const basePath = orgId ? orgId : `users/${userId}`;
460
+ if (isPublic) {
461
+ if (customPath) {
462
+ return `${basePath}/${customPath}/${fileName}`;
463
+ }
464
+ return `${basePath}/public/${fileName}`;
465
+ }
466
+ if (customPath) {
467
+ return `${basePath}/${customPath}/${fileName}`;
468
+ }
469
+ const pathFolder = customPath || "files";
470
+ return `${basePath}/${pathFolder}/${fileName}`;
471
+ }
472
+ function generateUniqueFileName(originalName) {
473
+ const timestamp = Date.now();
474
+ const uuid = crypto.randomUUID();
475
+ const extension = originalName.split(".").pop() || "";
476
+ let baseName = originalName.replace(/\.[^/.]+$/, "");
477
+ baseName = baseName.trim().replace(/\s+/g, "_").replace(/[<>:"/\\|?*]/g, "").replace(/\.\./g, "").replace(/^\.+|\.+$/g, "").substring(0, 200);
478
+ if (!extension || extension === originalName) {
479
+ return `${timestamp}-${uuid}-${baseName}`;
480
+ }
481
+ return `${timestamp}-${uuid}-${baseName}.${extension}`;
482
+ }
483
+ async function extractFileMetadata(file, options, uploadedBy) {
484
+ try {
485
+ const metadata = {
486
+ mimeType: file.type,
487
+ size: file.size,
488
+ ...options.orgId && { orgId: options.orgId },
489
+ ...options.userId && { userId: options.userId },
490
+ appName: options.appName || "pace-core",
491
+ uploadedBy,
492
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
493
+ tags: options.tags || [],
494
+ isPublic: options.isPublic || false,
495
+ customMetadata: options.metadata || {}
496
+ };
497
+ if (file.type.startsWith("image/")) {
498
+ try {
499
+ const dimensions = await getImageDimensions(file);
500
+ metadata.width = dimensions.width;
501
+ metadata.height = dimensions.height;
502
+ } catch (_error) {
503
+ }
504
+ }
505
+ try {
506
+ metadata.hash = await generateFileHash(file);
507
+ } catch (_error) {
508
+ }
509
+ return ok(metadata);
510
+ } catch (error) {
511
+ return err({
512
+ code: "EXTRACT_METADATA_FAILED",
513
+ message: error instanceof Error ? error.message : "Unknown error"
514
+ });
515
+ }
516
+ }
517
+ async function getImageDimensions(file) {
518
+ return new Promise((resolve, reject) => {
519
+ const img = new Image();
520
+ const url = URL.createObjectURL(file);
521
+ img.onload = () => {
522
+ URL.revokeObjectURL(url);
523
+ resolve({ width: img.width, height: img.height });
524
+ };
525
+ img.onerror = () => {
526
+ URL.revokeObjectURL(url);
527
+ reject(new Error("Could not load image"));
528
+ };
529
+ img.src = url;
530
+ });
531
+ }
532
+ async function generateFileHash(file) {
533
+ const buffer = await file.arrayBuffer();
534
+ const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
535
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
536
+ const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
537
+ return `sha256:${hashHex}`;
538
+ }
539
+ async function ensureFolderExists(supabase, folderPath, bucketName) {
540
+ try {
541
+ const { data, error } = await supabase.storage.from(bucketName).list(folderPath, {
542
+ limit: 1
543
+ });
544
+ if (!error) {
545
+ return true;
546
+ }
547
+ const placeholderPath = `${folderPath}/.keep`;
548
+ const placeholderBlob = new Blob([""], { type: "text/plain" });
549
+ const placeholderFile = new File([placeholderBlob], ".keep", { type: "text/plain" });
550
+ const { error: uploadError } = await supabase.storage.from(bucketName).upload(placeholderPath, placeholderFile, {
551
+ cacheControl: "3600",
552
+ upsert: true,
553
+ // Use upsert to avoid errors if file already exists
554
+ contentType: "text/plain"
555
+ });
556
+ if (uploadError) {
557
+ log2.debug(`Could not create folder placeholder (will be created on upload): ${uploadError.message}`);
558
+ return true;
559
+ }
560
+ return true;
561
+ } catch (error) {
562
+ log2.debug(`Folder creation exception (will be created on upload): ${error instanceof Error ? error.message : "Unknown error"}`);
563
+ return true;
564
+ }
565
+ }
566
+ async function uploadFile(supabase, file, options) {
567
+ try {
568
+ const sizeValidation = validateFileSize(file);
569
+ if (!sizeValidation.isValid) {
570
+ return err({ code: "FILE_SIZE_INVALID", message: sizeValidation.error ?? "File size validation failed" });
571
+ }
572
+ const uniqueFileName = generateUniqueFileName(file.name);
573
+ const filePath = generateFilePath(options, uniqueFileName);
574
+ const folderPath = filePath.substring(0, filePath.lastIndexOf("/"));
575
+ const metadataResult = await extractFileMetadata(file, options, "current-user");
576
+ if (!metadataResult.ok) {
577
+ return err(metadataResult.error);
578
+ }
579
+ const metadata = metadataResult.data;
580
+ const bucketName = getBucketName(options.isPublic || false);
581
+ await ensureFolderExists(supabase, folderPath, bucketName);
582
+ const { error } = await supabase.storage.from(bucketName).upload(filePath, file, {
583
+ cacheControl: "3600",
584
+ upsert: false,
585
+ contentType: file.type
586
+ });
587
+ if (error) {
588
+ return err({ code: "UPLOAD_FAILED", message: error.message });
589
+ }
590
+ let publicUrl;
591
+ if (options.isPublic) {
592
+ const { data: urlData } = supabase.storage.from(bucketName).getPublicUrl(filePath);
593
+ publicUrl = urlData.publicUrl;
594
+ }
595
+ return ok({ path: filePath, publicUrl, metadata });
596
+ } catch (error) {
597
+ return err({
598
+ code: "UPLOAD_FAILED",
599
+ message: error instanceof Error ? error.message : "Unknown error"
600
+ });
601
+ }
602
+ }
603
+ function getPublicUrl(supabase, path, isPublic = true) {
604
+ if (!supabase) {
605
+ throw new Error("Supabase client is required to generate a public URL");
606
+ }
607
+ if (!path || typeof path !== "string") {
608
+ throw new Error("A valid storage path is required to generate a public URL");
609
+ }
610
+ if (/^https?:\/\//i.test(path)) {
611
+ return path;
612
+ }
613
+ const normalisedPath = path.trim().replace(/^\/+/, "");
614
+ if (!normalisedPath) {
615
+ throw new Error("Storage path cannot be empty after normalisation");
616
+ }
617
+ const { bucketNameFromPath, storagePath } = resolveBucketHint(normalisedPath);
618
+ const bucketName = bucketNameFromPath || getBucketName(isPublic);
619
+ const { data } = supabase.storage.from(bucketName).getPublicUrl(storagePath);
620
+ return data.publicUrl;
621
+ }
622
+ function resolveBucketHint(pathWithPotentialBucket) {
623
+ const BUCKET_NAME_PATTERN = /^[a-z0-9][a-z0-9-_\.]{1,62}$/i;
624
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
625
+ const KNOWN_BUCKET_NAMES = /* @__PURE__ */ new Set(["files", "public-files"]);
626
+ const trimmedPath = pathWithPotentialBucket.trim();
627
+ if (!trimmedPath) {
628
+ throw new Error("Storage path cannot be empty after normalisation");
629
+ }
630
+ const doubleColonIndex = trimmedPath.indexOf("::");
631
+ if (doubleColonIndex > 0) {
632
+ const potentialBucket = trimmedPath.slice(0, doubleColonIndex).trim();
633
+ const remainingPath = trimmedPath.slice(doubleColonIndex + 2).replace(/^\/+/, "");
634
+ if (potentialBucket && remainingPath && BUCKET_NAME_PATTERN.test(potentialBucket)) {
635
+ return {
636
+ bucketNameFromPath: potentialBucket,
637
+ storagePath: remainingPath
638
+ };
639
+ }
640
+ }
641
+ const firstSlashIndex = trimmedPath.indexOf("/");
642
+ if (firstSlashIndex > 0) {
643
+ const potentialBucket = trimmedPath.slice(0, firstSlashIndex).trim();
644
+ const remainingPath = trimmedPath.slice(firstSlashIndex + 1).replace(/^\/+/, "");
645
+ if (potentialBucket && remainingPath && BUCKET_NAME_PATTERN.test(potentialBucket) && !UUID_PATTERN.test(potentialBucket) && (KNOWN_BUCKET_NAMES.has(potentialBucket) || !potentialBucket.includes("-")) && !/^\d+$/.test(potentialBucket)) {
646
+ return {
647
+ bucketNameFromPath: potentialBucket,
648
+ storagePath: remainingPath
649
+ };
650
+ }
651
+ }
652
+ return {
653
+ bucketNameFromPath: null,
654
+ storagePath: trimmedPath
655
+ };
656
+ }
657
+ async function getSignedUrl(supabase, path, options) {
658
+ try {
659
+ const bucketName = getBucketName(false);
660
+ const { data, error } = await supabase.storage.from(bucketName).createSignedUrl(path, options.expiresIn || 3600);
661
+ if (error) {
662
+ log2.error("Failed to create signed URL:", error);
663
+ return err({ code: "SIGNED_URL_FAILED", message: error.message });
664
+ }
665
+ return ok({
666
+ url: data.signedUrl,
667
+ expiresAt: new Date(Date.now() + (options.expiresIn || 3600) * 1e3).toISOString()
668
+ });
669
+ } catch (error) {
670
+ log2.error("Failed to create signed URL:", error);
671
+ return err({
672
+ code: "SIGNED_URL_FAILED",
673
+ message: error instanceof Error ? error.message : "Unknown error"
674
+ });
675
+ }
676
+ }
677
+ var globalUrlCache = /* @__PURE__ */ new Map();
678
+ var MAX_CACHE_SIZE = 500;
679
+ function getCacheKey(fileId, filePath, isPublic) {
680
+ return `file-url:${fileId}:${isPublic ? "public" : "private"}`;
681
+ }
682
+ function cleanupUrlCache() {
683
+ const now = Date.now();
684
+ for (const [key, value] of globalUrlCache.entries()) {
685
+ if (value.expiresAt < now) {
686
+ globalUrlCache.delete(key);
687
+ }
688
+ }
689
+ if (globalUrlCache.size > MAX_CACHE_SIZE) {
690
+ const entries = Array.from(globalUrlCache.entries());
691
+ entries.sort((a, b) => a[1].expiresAt - b[1].expiresAt);
692
+ const toRemove = Math.floor(MAX_CACHE_SIZE * 0.2);
693
+ for (let i = 0; i < toRemove && i < entries.length; i++) {
694
+ globalUrlCache.delete(entries[i][0]);
695
+ }
696
+ }
697
+ }
698
+ async function generateFileUrlsBatch(supabase, fileReferences, options) {
699
+ try {
700
+ const urlMap = /* @__PURE__ */ new Map();
701
+ if (fileReferences.length === 0) {
702
+ return ok(urlMap);
703
+ }
704
+ const now = Date.now();
705
+ const ttl = (options.expiresIn || 3600) * 1e3;
706
+ const publicFiles = [];
707
+ const privateFiles = [];
708
+ const uncachedFiles = [];
709
+ for (const fileRef of fileReferences) {
710
+ const cacheKey = getCacheKey(fileRef.id, fileRef.file_path, fileRef.is_public);
711
+ const cached = globalUrlCache.get(cacheKey);
712
+ if (cached && cached.expiresAt > now) {
713
+ urlMap.set(fileRef.id, cached.url);
714
+ continue;
715
+ }
716
+ if (fileRef.is_public) {
717
+ publicFiles.push({ id: fileRef.id, file_path: fileRef.file_path });
718
+ } else {
719
+ privateFiles.push({ id: fileRef.id, file_path: fileRef.file_path });
720
+ }
721
+ uncachedFiles.push(fileRef);
722
+ }
723
+ for (const file of publicFiles) {
724
+ try {
725
+ const url = getPublicUrl(supabase, file.file_path, true);
726
+ if (url) {
727
+ urlMap.set(file.id, url);
728
+ const cacheKey = getCacheKey(file.id, file.file_path, true);
729
+ globalUrlCache.set(cacheKey, { url, expiresAt: now + ttl });
730
+ }
731
+ } catch (e) {
732
+ log2.error(`Failed to generate public URL for file ${file.id}:`, e);
733
+ }
734
+ }
735
+ if (privateFiles.length > 0) {
736
+ const signedUrlPromises = privateFiles.map(async (file) => {
737
+ const signedUrlResult = await getSignedUrl(supabase, file.file_path, {
738
+ appName: options.appName || "pace-core",
739
+ orgId: options.orgId,
740
+ expiresIn: options.expiresIn || 3600
741
+ });
742
+ const url = signedUrlResult.ok ? signedUrlResult.data.url : null;
743
+ if (url) {
744
+ const cacheKey = getCacheKey(file.id, file.file_path, false);
745
+ globalUrlCache.set(cacheKey, { url, expiresAt: now + ttl });
746
+ }
747
+ return { id: file.id, url };
748
+ });
749
+ const signedUrlResults = await Promise.all(signedUrlPromises);
750
+ for (const result of signedUrlResults) {
751
+ if (result.url) {
752
+ urlMap.set(result.id, result.url);
753
+ }
754
+ }
755
+ }
756
+ if (uncachedFiles.length > 0) {
757
+ cleanupUrlCache();
758
+ }
759
+ return ok(urlMap);
760
+ } catch (error) {
761
+ return err({
762
+ code: "BATCH_URLS_FAILED",
763
+ message: error instanceof Error ? error.message : "Unknown error"
764
+ });
765
+ }
766
+ }
767
+ async function deleteFile(supabase, path, isPublic = false) {
768
+ try {
769
+ const bucketName = getBucketName(isPublic);
770
+ const { error } = await supabase.storage.from(bucketName).remove([path]);
771
+ if (error) {
772
+ return err({ code: "DELETE_FAILED", message: error.message });
773
+ }
774
+ return ok(void 0);
775
+ } catch (error) {
776
+ return err({
777
+ code: "DELETE_FAILED",
778
+ message: error instanceof Error ? error.message : "Unknown error"
779
+ });
780
+ }
781
+ }
782
+ async function listFiles(supabase, options) {
783
+ try {
784
+ const bucketName = getBucketName(options.isPublic || false);
785
+ if (!options.orgId && !options.userId) {
786
+ return err({ code: "LIST_FILES_INVALID_OPTIONS", message: "Either orgId or userId is required for listing files" });
787
+ }
788
+ const basePath = options.orgId ? options.orgId : `users/${options.userId}`;
789
+ const pathPrefix = `${basePath}/`;
790
+ const searchPath = options.pathPrefix ? `${pathPrefix}${options.pathPrefix}` : pathPrefix;
791
+ const { data, error } = await supabase.storage.from(bucketName).list(searchPath, {
792
+ limit: options.limit || 100,
793
+ offset: options.offset || 0,
794
+ sortBy: { column: "created_at", order: "desc" }
795
+ });
796
+ if (error) {
797
+ log2.error("Failed to list files:", error);
798
+ return err({ code: "LIST_FILES_FAILED", message: error.message });
799
+ }
800
+ const files = (data || []).map((item) => ({
801
+ name: item.name,
802
+ path: `${searchPath}${item.name}`,
803
+ size: item.metadata?.size || 0,
804
+ mimeType: item.metadata?.mimetype || "application/octet-stream",
805
+ lastModified: item.updated_at || item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
806
+ metadata: {
807
+ mimeType: item.metadata?.mimetype || "application/octet-stream",
808
+ size: item.metadata?.size || 0,
809
+ ...options.orgId && { orgId: options.orgId },
810
+ ...options.userId && { userId: options.userId },
811
+ appName: options.appName,
812
+ uploadedBy: "unknown",
813
+ uploadedAt: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
814
+ isPublic: options.isPublic || false
815
+ }
816
+ }));
817
+ return ok({
818
+ files,
819
+ totalCount: files.length,
820
+ hasMore: files.length >= (options.limit || 100)
821
+ });
822
+ } catch (error) {
823
+ log2.error("Failed to list files:", error);
824
+ return err({
825
+ code: "LIST_FILES_FAILED",
826
+ message: error instanceof Error ? error.message : "Unknown error"
827
+ });
828
+ }
829
+ }
830
+ async function downloadFile(supabase, path, isPublic = false) {
831
+ try {
832
+ const bucketName = getBucketName(isPublic);
833
+ const { data, error } = await supabase.storage.from(bucketName).download(path);
834
+ if (error) {
835
+ log2.error("Failed to download file:", error);
836
+ return err({ code: "DOWNLOAD_FAILED", message: error.message });
837
+ }
838
+ if (!data) {
839
+ return err({ code: "DOWNLOAD_FAILED", message: "No data returned" });
840
+ }
841
+ const fileName = path.split("/").pop() || "download";
842
+ const { data: fileInfo } = await supabase.storage.from(bucketName).list(path.split("/").slice(0, -1).join("/"), { search: fileName });
843
+ const metadata = fileInfo?.[0]?.metadata || {};
844
+ return ok({
845
+ blob: data,
846
+ metadata: {
847
+ name: fileName,
848
+ size: metadata.size || data.size,
849
+ type: metadata.mimetype || "application/octet-stream"
850
+ }
851
+ });
852
+ } catch (error) {
853
+ log2.error("Failed to download file:", error);
854
+ return err({
855
+ code: "DOWNLOAD_FAILED",
856
+ message: error instanceof Error ? error.message : "Unknown error"
857
+ });
858
+ }
859
+ }
860
+ async function archiveFile(supabase, path, options) {
861
+ try {
862
+ const bucketName = getBucketName(options.isPublic || false);
863
+ let archivedPath;
864
+ if (options.orgId) {
865
+ archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
866
+ } else if (options.userId) {
867
+ archivedPath = path.replace(`users/${options.userId}/`, `archived/users/${options.userId}/`);
868
+ } else {
869
+ return err({ code: "ARCHIVE_FAILED", message: "Either orgId or userId is required for archiving files" });
870
+ }
871
+ const { error: copyError } = await supabase.storage.from(bucketName).copy(path, archivedPath);
872
+ if (copyError) {
873
+ return err({ code: "ARCHIVE_FAILED", message: copyError.message });
874
+ }
875
+ const deleteResult = await deleteFile(supabase, path, options.isPublic || false);
876
+ if (!deleteResult.ok) {
877
+ return err(deleteResult.error);
878
+ }
879
+ return ok(void 0);
880
+ } catch (error) {
881
+ return err({
882
+ code: "ARCHIVE_FAILED",
883
+ message: error instanceof Error ? error.message : "Unknown error"
884
+ });
885
+ }
886
+ }
887
+ var publicFileCache = /* @__PURE__ */ new Map();
888
+ function usePublicFileDisplay(table_name, record_id, organisation_id, category, options) {
889
+ const {
890
+ cacheTtl = 30 * 60 * 1e3,
891
+ // 30 minutes
892
+ enableCache = true,
893
+ supabase
894
+ } = options;
895
+ const [fileUrl, setFileUrl] = useState(null);
896
+ const [fileReference, setFileReference] = useState(null);
897
+ const [fileReferences, setFileReferences] = useState([]);
898
+ const [fileUrls, setFileUrls] = useState(/* @__PURE__ */ new Map());
899
+ const [fileCount, setFileCount] = useState(0);
900
+ const [isLoading, setIsLoading] = useState(false);
901
+ const [error, setError] = useState(null);
902
+ const fetchFiles = useCallback(async () => {
903
+ const emptySetters = () => {
904
+ applyEmptyPublicFileState(
905
+ setFileUrl,
906
+ setFileReference,
907
+ setFileReferences,
908
+ setFileUrls,
909
+ setFileCount,
910
+ setIsLoading,
911
+ setError
912
+ );
913
+ };
914
+ if (!table_name || !record_id || !supabase) {
915
+ emptySetters();
916
+ return;
917
+ }
918
+ warnInvalidOrganisationIdUuid(organisation_id ?? void 0);
919
+ const cacheKey = buildPublicFileCacheKey(table_name, record_id, organisation_id, category);
920
+ const cached = getCachedPublicFileData(cacheKey, enableCache);
921
+ if (cached) {
922
+ applyCachedPublicFileState(
923
+ cached,
924
+ setFileUrl,
925
+ setFileReference,
926
+ setFileReferences,
927
+ setFileUrls,
928
+ setFileCount,
929
+ setIsLoading,
930
+ setError
931
+ );
932
+ return;
933
+ }
934
+ try {
935
+ setIsLoading(true);
936
+ setError(null);
937
+ const rows = await fetchPublicFileRows(supabase, table_name, record_id, organisation_id, category);
938
+ const publicRows = rows.filter((f) => f.is_public === true);
939
+ if (publicRows.length === 0) {
940
+ emptySetters();
941
+ setCachedPublicFileData(cacheKey, emptyCacheData, enableCache, cacheTtl);
942
+ return;
943
+ }
944
+ const fileRefs = mapDbRowsToFileReferences(publicRows);
945
+ setFileReferences(fileRefs);
946
+ setFileCount(fileRefs.length);
947
+ if (category && fileRefs.length > 0) {
948
+ const firstFile = fileRefs[0];
949
+ setFileReference(firstFile);
950
+ setFileUrl(getPublicUrl(supabase, firstFile.file_path, true));
951
+ } else {
952
+ const urlResult = await generateFileUrlsBatch(supabase, fileRefs, {
953
+ appName: "pace-core",
954
+ orgId: organisation_id,
955
+ expiresIn: 3600
956
+ });
957
+ setFileUrls(urlResult.ok ? urlResult.data : /* @__PURE__ */ new Map());
958
+ setFileReference(null);
959
+ setFileUrl(null);
960
+ }
961
+ setCachedPublicFileData(
962
+ cacheKey,
963
+ buildCacheDataFromRefs(fileRefs, category, supabase),
964
+ enableCache,
965
+ cacheTtl
966
+ );
967
+ } catch (err2) {
968
+ logger.error("usePublicFileDisplay", "Error fetching files", {
969
+ table_name,
970
+ record_id,
971
+ organisation_id,
972
+ category,
973
+ error: err2 instanceof Error ? err2.message : "Unknown error",
974
+ errorDetails: err2 instanceof Error ? err2.stack : String(err2)
975
+ });
976
+ const error2 = err2 instanceof Error ? err2 : new Error("Unknown error occurred");
977
+ setError(error2);
978
+ setFileUrl(null);
979
+ setFileReference(null);
980
+ setFileReferences([]);
981
+ setFileUrls(/* @__PURE__ */ new Map());
982
+ setFileCount(0);
983
+ } finally {
984
+ setIsLoading(false);
985
+ }
986
+ }, [table_name, record_id, organisation_id, category, supabase, cacheTtl, enableCache]);
987
+ useEffect(() => {
988
+ if (table_name && record_id) {
989
+ fetchFiles();
990
+ } else {
991
+ setFileUrl(null);
992
+ setFileReference(null);
993
+ setFileReferences([]);
994
+ setFileUrls(/* @__PURE__ */ new Map());
995
+ setFileCount(0);
996
+ setIsLoading(false);
997
+ setError(null);
998
+ }
999
+ }, [fetchFiles, table_name, record_id, organisation_id]);
1000
+ const refetch = useCallback(async () => {
1001
+ if (!table_name || !record_id) return;
1002
+ if (enableCache) {
1003
+ const cacheKey = buildPublicFileCacheKey(table_name, record_id, organisation_id, category);
1004
+ publicFileCache.delete(cacheKey);
1005
+ }
1006
+ await fetchFiles();
1007
+ }, [fetchFiles, table_name, record_id, organisation_id, category, enableCache]);
1008
+ return {
1009
+ fileUrl,
1010
+ fileReference,
1011
+ fileReferences,
1012
+ fileUrls,
1013
+ fileCount,
1014
+ isLoading,
1015
+ error,
1016
+ refetch
1017
+ };
1018
+ }
1019
+ function buildPublicFileCacheKey(table_name, record_id, organisation_id, category) {
1020
+ return `public_file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1021
+ }
1022
+ function getCachedPublicFileData(cacheKey, enableCache) {
1023
+ if (!enableCache) return null;
1024
+ const cached = publicFileCache.get(cacheKey);
1025
+ if (!cached || Date.now() - cached.timestamp >= cached.ttl) return null;
1026
+ return cached.data;
1027
+ }
1028
+ function setCachedPublicFileData(cacheKey, data, enableCache, cacheTtl) {
1029
+ if (!enableCache) return;
1030
+ publicFileCache.set(cacheKey, {
1031
+ data,
1032
+ timestamp: Date.now(),
1033
+ ttl: cacheTtl
1034
+ });
1035
+ }
1036
+ function mapRpcItemToRow(item, table_name, record_id, organisation_id) {
1037
+ const metadata = item.file_metadata;
1038
+ return {
1039
+ id: item.id,
1040
+ table_name,
1041
+ record_id,
1042
+ file_path: item.file_path,
1043
+ file_metadata: item.file_metadata || null,
1044
+ organisation_id,
1045
+ app_id: metadata?.app_id || "",
1046
+ is_public: true,
1047
+ created_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1048
+ updated_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1049
+ created_by: null
1050
+ };
1051
+ }
1052
+ async function fetchPublicFileRowsWhenOrgUndefined(supabase, table_name, record_id, category) {
1053
+ let userScopedFiles = [];
1054
+ const orgScopedFiles = [];
1055
+ logger.debug("usePublicFileDisplay", "organisation_id is undefined, searching both user-scoped and organisation-scoped files:", {
1056
+ table_name,
1057
+ record_id,
1058
+ category
1059
+ });
1060
+ if (category) {
1061
+ const { data: userData, error: userRpcError } = await supabase.rpc("data_file_reference_by_category_list", {
1062
+ p_table_name: table_name,
1063
+ p_record_id: record_id,
1064
+ p_category: category,
1065
+ p_organisation_id: void 0
1066
+ });
1067
+ if (!userRpcError && userData) {
1068
+ userScopedFiles = userData.filter((item) => item.is_public === true && item.id && item.file_path && item.file_metadata).map((item) => mapRpcItemToRow(item, table_name, record_id, null));
1069
+ }
1070
+ } else {
1071
+ const { data: userData, error: userRpcError } = await supabase.rpc("data_file_reference_list", {
1072
+ p_table_name: table_name,
1073
+ p_record_id: record_id,
1074
+ p_organisation_id: void 0
1075
+ });
1076
+ if (!userRpcError && userData) {
1077
+ const ids = userData.map((item) => item.id);
1078
+ if (ids.length > 0) {
1079
+ const { data: fullData } = await supabase.from("core_file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at, created_by").in("id", ids).eq("is_public", true);
1080
+ userScopedFiles = fullData || [];
1081
+ }
1082
+ }
1083
+ }
1084
+ const allFiles = [...userScopedFiles, ...orgScopedFiles];
1085
+ allFiles.sort((a, b) => {
1086
+ const aTime = new Date(a.created_at || 0).getTime();
1087
+ const bTime = new Date(b.created_at || 0).getTime();
1088
+ return bTime - aTime;
1089
+ });
1090
+ logger.debug("usePublicFileDisplay", "Found files with undefined organisation_id:", {
1091
+ userScopedCount: userScopedFiles.length,
1092
+ orgScopedCount: orgScopedFiles.length,
1093
+ totalCount: allFiles.length
1094
+ });
1095
+ return allFiles;
1096
+ }
1097
+ async function fetchPublicFileRowsWhenOrgDefined(supabase, table_name, record_id, organisation_id, category) {
1098
+ if (category) {
1099
+ const rpcParams = {
1100
+ p_table_name: table_name,
1101
+ p_record_id: record_id,
1102
+ p_category: category,
1103
+ p_organisation_id: organisation_id ?? void 0
1104
+ };
1105
+ const { data, error: rpcError2 } = await supabase.rpc("data_file_reference_by_category_list", rpcParams);
1106
+ if (rpcError2) {
1107
+ logger.error("usePublicFileDisplay", "RPC function error", {
1108
+ function: "data_file_reference_by_category_list",
1109
+ table_name,
1110
+ record_id,
1111
+ category,
1112
+ organisation_id,
1113
+ error: rpcError2.message,
1114
+ errorCode: rpcError2.code,
1115
+ errorDetails: rpcError2.details,
1116
+ errorHint: rpcError2.hint
1117
+ });
1118
+ throw new Error(rpcError2.message || "Failed to fetch file reference");
1119
+ }
1120
+ if (!data || data.length === 0) return [];
1121
+ return data.filter((item) => item.is_public === true && item.id && item.file_path && item.file_metadata).map((item) => mapRpcItemToRow(item, table_name, record_id, organisation_id ?? null));
1122
+ }
1123
+ const { data: fileIds, error: rpcError } = await supabase.rpc("data_file_reference_list", {
1124
+ p_table_name: table_name,
1125
+ p_record_id: record_id,
1126
+ p_organisation_id: organisation_id ?? void 0
1127
+ });
1128
+ if (rpcError) {
1129
+ logger.error("usePublicFileDisplay", "RPC function error", {
1130
+ function: "data_file_reference_list",
1131
+ table_name,
1132
+ record_id,
1133
+ organisation_id,
1134
+ error: rpcError.message,
1135
+ errorCode: rpcError.code,
1136
+ errorDetails: rpcError.details,
1137
+ errorHint: rpcError.hint
1138
+ });
1139
+ throw new Error(rpcError.message || "Failed to fetch file references");
1140
+ }
1141
+ if (!fileIds || fileIds.length === 0) return [];
1142
+ const ids = fileIds.map((item) => item.id);
1143
+ const { data: fullData, error: fetchError } = await supabase.from("core_file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at, created_by").in("id", ids).eq("is_public", true);
1144
+ if (fetchError) throw new Error(fetchError.message || "Failed to fetch file references");
1145
+ return fullData || [];
1146
+ }
1147
+ async function fetchPublicFileRows(supabase, table_name, record_id, organisation_id, category) {
1148
+ if (organisation_id === void 0) {
1149
+ return fetchPublicFileRowsWhenOrgUndefined(supabase, table_name, record_id, category);
1150
+ }
1151
+ return fetchPublicFileRowsWhenOrgDefined(supabase, table_name, record_id, organisation_id, category);
1152
+ }
1153
+ function mapDbRowsToFileReferences(rows) {
1154
+ return rows.map((f) => {
1155
+ const fileName = f.file_path.split("/").pop() || "unknown";
1156
+ const fileType = fileName.split(".").pop() || "unknown";
1157
+ const metadata = f.file_metadata;
1158
+ return {
1159
+ id: f.id,
1160
+ table_name: f.table_name,
1161
+ record_id: f.record_id,
1162
+ file_path: f.file_path,
1163
+ file_metadata: {
1164
+ fileName: metadata?.fileName || fileName,
1165
+ fileType: metadata?.fileType || fileType,
1166
+ category: metadata?.category || "general_documents" /* GENERAL_DOCUMENTS */,
1167
+ ...metadata || {}
1168
+ },
1169
+ organisation_id: f.organisation_id,
1170
+ app_id: f.app_id,
1171
+ is_public: f.is_public ?? true,
1172
+ created_at: f.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1173
+ updated_at: f.updated_at || (/* @__PURE__ */ new Date()).toISOString()
1174
+ };
1175
+ });
1176
+ }
1177
+ function buildCacheDataFromRefs(fileRefs, category, supabase) {
1178
+ const fileUrl = category && fileRefs.length > 0 ? getPublicUrl(supabase, fileRefs[0].file_path, true) : null;
1179
+ const fileReference = category && fileRefs.length > 0 ? fileRefs[0] : null;
1180
+ let fileUrls;
1181
+ if (category) {
1182
+ fileUrls = /* @__PURE__ */ new Map();
1183
+ } else {
1184
+ fileUrls = /* @__PURE__ */ new Map();
1185
+ for (const fileRef of fileRefs) {
1186
+ const url = getPublicUrl(supabase, fileRef.file_path, true);
1187
+ if (url) fileUrls.set(fileRef.id, url);
1188
+ }
1189
+ }
1190
+ return {
1191
+ fileUrl,
1192
+ fileReference,
1193
+ fileReferences: fileRefs,
1194
+ fileUrls,
1195
+ fileCount: fileRefs.length
1196
+ };
1197
+ }
1198
+ var emptyCacheData = {
1199
+ fileUrl: null,
1200
+ fileReference: null,
1201
+ fileReferences: [],
1202
+ fileUrls: /* @__PURE__ */ new Map(),
1203
+ fileCount: 0
1204
+ };
1205
+ function applyEmptyPublicFileState(setFileUrl, setFileReference, setFileReferences, setFileUrls, setFileCount, setIsLoading, setError) {
1206
+ setFileUrl(null);
1207
+ setFileReference(null);
1208
+ setFileReferences([]);
1209
+ setFileUrls(/* @__PURE__ */ new Map());
1210
+ setFileCount(0);
1211
+ setIsLoading(false);
1212
+ setError(null);
1213
+ }
1214
+ function applyCachedPublicFileState(cachedData, setFileUrl, setFileReference, setFileReferences, setFileUrls, setFileCount, setIsLoading, setError) {
1215
+ setFileUrl(cachedData.fileUrl || null);
1216
+ setFileReference(cachedData.fileReference || null);
1217
+ setFileReferences(cachedData.fileReferences || []);
1218
+ setFileUrls(cachedData.fileUrls || /* @__PURE__ */ new Map());
1219
+ setFileCount(cachedData.fileCount || 0);
1220
+ setIsLoading(false);
1221
+ setError(null);
1222
+ }
1223
+ function warnInvalidOrganisationIdUuid(organisation_id) {
1224
+ if (!organisation_id) return;
1225
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1226
+ if (!uuidRegex.test(organisation_id)) {
1227
+ logger.warn("usePublicFileDisplay", "Invalid organisationId format (not a valid UUID)", { organisation_id });
1228
+ }
1229
+ }
1230
+ function clearPublicFileDisplayCache() {
1231
+ for (const [key] of publicFileCache) {
1232
+ if (key.startsWith("public_file_")) {
1233
+ publicFileCache.delete(key);
1234
+ }
1235
+ }
1236
+ }
1237
+ function getPublicFileDisplayCacheStats() {
1238
+ const keys = Array.from(publicFileCache.keys()).filter((key) => key.startsWith("public_file_"));
1239
+ return {
1240
+ size: keys.length,
1241
+ keys
1242
+ };
1243
+ }
1244
+
1245
+ // src/utils/file-reference/index.ts
1246
+ var log3 = createLogger("FileReferenceService");
1247
+ function toApiError(error) {
1248
+ const message = error instanceof Error ? error.message : "Unknown error";
1249
+ const code = error instanceof Error && error.code ? error.code : "FILE_REFERENCE_ERROR";
1250
+ return { code, message };
1251
+ }
1252
+ function mapFileReferenceRowToFileReference(f) {
1253
+ const fileName = f.file_path.split("/").pop() || "unknown";
1254
+ const fileType = fileName.split(".").pop() || "unknown";
1255
+ const metadata = f.file_metadata;
1256
+ return {
1257
+ id: f.id,
1258
+ table_name: f.table_name,
1259
+ record_id: f.record_id,
1260
+ file_path: f.file_path,
1261
+ file_metadata: {
1262
+ fileName: metadata?.fileName || fileName,
1263
+ fileType: metadata?.fileType || fileType,
1264
+ category: metadata?.category || "general_documents" /* GENERAL_DOCUMENTS */,
1265
+ ...metadata || {}
1266
+ },
1267
+ organisation_id: f.organisation_id,
1268
+ app_id: f.app_id,
1269
+ is_public: f.is_public ?? false,
1270
+ created_at: f.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1271
+ updated_at: f.updated_at || (/* @__PURE__ */ new Date()).toISOString()
1272
+ };
1273
+ }
1274
+ var FileReferenceServiceImpl = class {
1275
+ constructor(supabase) {
1276
+ this.supabase = supabase;
1277
+ }
1278
+ /**
1279
+ * Helper method to get app name from app ID
1280
+ */
1281
+ async getAppName(appId) {
1282
+ try {
1283
+ const { data, error } = await this.supabase.from("rbac_apps").select("name").eq("id", appId).single();
1284
+ if (error || !data) {
1285
+ return "unknown";
1286
+ }
1287
+ return data.name || "unknown";
1288
+ } catch {
1289
+ return "unknown";
1290
+ }
1291
+ }
1292
+ validateCreateOptions(options) {
1293
+ const isUserScoped = !options.organisation_id && !!options.userId;
1294
+ if (!isUserScoped && !options.organisation_id) {
1295
+ return err({ code: "VALIDATION_ERROR", message: "organisation_id is required for file upload, or userId must be provided for user-scoped files" });
1296
+ }
1297
+ if (!options.table_name) {
1298
+ return err({ code: "VALIDATION_ERROR", message: "table_name is required for file upload" });
1299
+ }
1300
+ if (!options.record_id) {
1301
+ return err({ code: "VALIDATION_ERROR", message: "record_id is required for file upload" });
1302
+ }
1303
+ if (!options.folder) {
1304
+ return err({ code: "VALIDATION_ERROR", message: "folder is required for file upload. The folder prop determines the storage path." });
1305
+ }
1306
+ return ok({ isUserScoped });
1307
+ }
1308
+ async resolveAuthenticatedUserIdForUserScoped() {
1309
+ const { data: { user: authUser }, error: authError } = await this.supabase.auth.getUser();
1310
+ if (authError || !authUser) {
1311
+ return err({ code: "UNAUTHORIZED", message: "User must be authenticated to upload user-scoped files" });
1312
+ }
1313
+ log3.debug("Using authenticated user ID for user-scoped file upload", { userId: authUser.id });
1314
+ return ok(authUser.id);
1315
+ }
1316
+ async checkSuperAdminUser(userId) {
1317
+ if (!userId) return false;
1318
+ try {
1319
+ const { isSuperAdmin } = await import('./api-6OQXYT67.js');
1320
+ const superResult = await isSuperAdmin(userId);
1321
+ if (superResult.ok && superResult.data) {
1322
+ log3.debug("Super admin detected - bypassing permission checks", { userId });
1323
+ return true;
1324
+ }
1325
+ return false;
1326
+ } catch (superAdminCheckError) {
1327
+ log3.warn("Failed to check super-admin status, proceeding with normal permission checks", superAdminCheckError);
1328
+ return false;
1329
+ }
1330
+ }
1331
+ async uploadFileAndExtractMetadata(options, file, authenticatedUserId, isUserScoped) {
1332
+ const userId = authenticatedUserId || (isUserScoped ? void 0 : options.userId);
1333
+ const uploadResult = await uploadFile(this.supabase, file, {
1334
+ appName: "file-reference",
1335
+ orgId: options.organisation_id || void 0,
1336
+ userId,
1337
+ isPublic: options.is_public || false,
1338
+ customPath: options.folder
1339
+ });
1340
+ if (!uploadResult.ok) return err(uploadResult.error);
1341
+ const metadataResult = await extractFileMetadata(file, {
1342
+ appName: "file-reference",
1343
+ orgId: options.organisation_id || void 0,
1344
+ userId,
1345
+ isPublic: options.is_public || false
1346
+ }, "system");
1347
+ if (!metadataResult.ok) return err(metadataResult.error);
1348
+ return ok({ path: uploadResult.data.path, metadata: metadataResult.data });
1349
+ }
1350
+ async setOrgContextIfNeeded(isUserScoped, organisation_id) {
1351
+ if (isUserScoped || !organisation_id) return;
1352
+ const ctxResult = await setOrganisationContext(this.supabase, organisation_id);
1353
+ if (!ctxResult.ok) {
1354
+ log3.warn("setOrganisationContext failed (non-fatal):", ctxResult.error.message);
1355
+ }
1356
+ }
1357
+ async resolveRpcUserId(authenticatedUserId, options) {
1358
+ if (authenticatedUserId) return authenticatedUserId;
1359
+ if (options.userId) return options.userId;
1360
+ const { data: { user: authUser } } = await this.supabase.auth.getUser();
1361
+ return authUser?.id ?? null;
1362
+ }
1363
+ async buildPermissionDeniedMessage(options, isSuperAdminUser) {
1364
+ const appName = await this.getAppName(options.app_id).catch(() => "unknown");
1365
+ const pageContextDisplay = options.pageContext || "undefined";
1366
+ return isSuperAdminUser ? `File upload failed for super-admin user. Page context: '${pageContextDisplay}', App: '${appName}'.` : `File upload denied: insufficient permissions. You need 'create:page.${pageContextDisplay}' or 'update:page.${pageContextDisplay}' for the '${pageContextDisplay}' page.`;
1367
+ }
1368
+ async rollbackUploadAndErr(filePath, isPublic, code, message) {
1369
+ await deleteFile(this.supabase, filePath, isPublic);
1370
+ return err({ code, message });
1371
+ }
1372
+ async fetchCreatedFileReference(createdId) {
1373
+ const { data: fileRef, error: fetchError } = await this.supabase.from("core_file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("id", createdId).single();
1374
+ if (fetchError || !fileRef) {
1375
+ return err({ code: "FETCH_FAILED", message: fetchError?.message ?? "Failed to fetch created file reference" });
1376
+ }
1377
+ return ok(fileRef);
1378
+ }
1379
+ buildCreateRpcPayload(options, filePath, file, metadata, rpcUserId) {
1380
+ return {
1381
+ p_table_name: options.table_name,
1382
+ p_record_id: options.record_id,
1383
+ p_file_path: filePath,
1384
+ p_organisation_id: options.organisation_id ?? null,
1385
+ p_app_id: options.app_id,
1386
+ p_page_context: options.pageContext,
1387
+ p_event_id: options.event_id || null,
1388
+ p_file_metadata: {
1389
+ fileName: file.name,
1390
+ fileType: file.type,
1391
+ fileSize: file.size,
1392
+ category: options.category,
1393
+ ...metadata,
1394
+ ...options.custom_metadata
1395
+ },
1396
+ p_is_public: options.is_public || false,
1397
+ p_user_id: rpcUserId
1398
+ };
1399
+ }
1400
+ /**
1401
+ * Creates a file reference by uploading a file to storage and linking it in the database.
1402
+ *
1403
+ * Storage Flow:
1404
+ * 1. Upload file to storage bucket first (files or public-files based on is_public flag)
1405
+ * - Path format: {orgId}/{folder}/{timestamp-uuid-filename}
1406
+ * - Bucket selection: 'files' (private) or 'public-files' (public)
1407
+ * 2. Extract file metadata (dimensions, hash, etc.)
1408
+ * 3. Set organisation context for RLS policies
1409
+ * 4. Create database reference via RPC function
1410
+ * 5. If DB insert fails, rollback by deleting uploaded file
1411
+ *
1412
+ * This ensures atomicity: either both storage and DB succeed, or both are cleaned up.
1413
+ */
1414
+ async createFileReference(options, file) {
1415
+ try {
1416
+ const validation = this.validateCreateOptions(options);
1417
+ if (!validation.ok) return validation;
1418
+ const { isUserScoped } = validation.data;
1419
+ let authenticatedUserId;
1420
+ if (isUserScoped) {
1421
+ const authResult = await this.resolveAuthenticatedUserIdForUserScoped();
1422
+ if (!authResult.ok) return authResult;
1423
+ authenticatedUserId = authResult.data;
1424
+ }
1425
+ const isSuperAdminUser = await this.checkSuperAdminUser(authenticatedUserId || options.userId);
1426
+ const uploadResult = await this.uploadFileAndExtractMetadata(options, file, authenticatedUserId, isUserScoped);
1427
+ if (!uploadResult.ok) return uploadResult;
1428
+ const { path: filePath, metadata } = uploadResult.data;
1429
+ await this.setOrgContextIfNeeded(isUserScoped, options.organisation_id ?? void 0);
1430
+ const rpcUserId = await this.resolveRpcUserId(authenticatedUserId, options);
1431
+ const payload = this.buildCreateRpcPayload(options, filePath, file, metadata, rpcUserId);
1432
+ const { data, error } = await this.supabase.rpc("data_file_reference_create", payload);
1433
+ if (error) {
1434
+ return await this.rollbackUploadAndErr(filePath, options.is_public ?? false, "CREATE_FAILED", error.message);
1435
+ }
1436
+ if (!data || data === null) {
1437
+ const message = await this.buildPermissionDeniedMessage(options, isSuperAdminUser);
1438
+ return await this.rollbackUploadAndErr(filePath, options.is_public ?? false, "PERMISSION_DENIED", message);
1439
+ }
1440
+ const fetchResult = await this.fetchCreatedFileReference(data);
1441
+ if (!fetchResult.ok) {
1442
+ return await this.rollbackUploadAndErr(
1443
+ filePath,
1444
+ options.is_public ?? false,
1445
+ "FETCH_FAILED",
1446
+ fetchResult.error.message
1447
+ );
1448
+ }
1449
+ invalidateFileDisplayCache(
1450
+ options.table_name,
1451
+ options.record_id,
1452
+ options.organisation_id || null,
1453
+ options.category
1454
+ );
1455
+ return ok(fetchResult.data);
1456
+ } catch (error) {
1457
+ log3.error("Error creating file reference:", error);
1458
+ return err(toApiError(error));
1459
+ }
1460
+ }
1461
+ async getFileReference(table_name, record_id, organisation_id) {
1462
+ try {
1463
+ let query = this.supabase.from("core_file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("table_name", table_name).eq("record_id", record_id);
1464
+ if (organisation_id === null || organisation_id === void 0) {
1465
+ query = query.is("organisation_id", null);
1466
+ } else {
1467
+ query = query.eq("organisation_id", organisation_id);
1468
+ }
1469
+ const { data, error } = await query.single();
1470
+ if (error) {
1471
+ if (error.code === "PGRST116") {
1472
+ return ok(null);
1473
+ }
1474
+ return err({ code: "FETCH_FAILED", message: error.message });
1475
+ }
1476
+ return ok(data);
1477
+ } catch (error) {
1478
+ log3.error("Error getting file reference:", error);
1479
+ return err(toApiError(error));
1480
+ }
1481
+ }
1482
+ async getFileUrl(table_name, record_id, organisation_id) {
1483
+ try {
1484
+ const refResult = await this.getFileReference(table_name, record_id, organisation_id);
1485
+ if (!refResult.ok) {
1486
+ return refResult;
1487
+ }
1488
+ const fileRef = refResult.data;
1489
+ if (!fileRef) {
1490
+ return ok(null);
1491
+ }
1492
+ if (fileRef.is_public) {
1493
+ const { data: pathData } = await this.supabase.rpc("data_file_reference_url_get", {
1494
+ p_table_name: table_name,
1495
+ p_record_id: record_id,
1496
+ p_organisation_id: organisation_id
1497
+ });
1498
+ if (!pathData) {
1499
+ return ok(null);
1500
+ }
1501
+ return ok(getPublicUrl(this.supabase, pathData, true));
1502
+ }
1503
+ return this.getSignedUrl(table_name, record_id, organisation_id);
1504
+ } catch (error) {
1505
+ log3.error("Error getting file URL:", error);
1506
+ return err(toApiError(error));
1507
+ }
1508
+ }
1509
+ async getSignedUrl(table_name, record_id, organisation_id, expires_in = 3600) {
1510
+ try {
1511
+ const { data: filePath, error } = await this.supabase.rpc("data_file_reference_signed_url_get", {
1512
+ p_table_name: table_name,
1513
+ p_record_id: record_id,
1514
+ p_organisation_id: organisation_id ?? null,
1515
+ p_expires_in: expires_in
1516
+ });
1517
+ if (error) {
1518
+ return err({ code: "SIGNED_URL_FAILED", message: error.message });
1519
+ }
1520
+ if (!filePath) {
1521
+ return ok(null);
1522
+ }
1523
+ const signedUrlResult = await getSignedUrl(this.supabase, filePath, {
1524
+ appName: "file-reference",
1525
+ orgId: organisation_id,
1526
+ userId: organisation_id ? void 0 : record_id,
1527
+ expiresIn: expires_in
1528
+ });
1529
+ if (!signedUrlResult.ok) {
1530
+ return err(signedUrlResult.error);
1531
+ }
1532
+ return ok(signedUrlResult.data.url ?? null);
1533
+ } catch (error) {
1534
+ log3.error("Error getting signed URL:", error);
1535
+ return err(toApiError(error));
1536
+ }
1537
+ }
1538
+ async updateFileReference(id, updates) {
1539
+ try {
1540
+ const { data, error } = await this.supabase.from("core_file_references").update(updates).eq("id", id).select().single();
1541
+ if (error) {
1542
+ return err({ code: "UPDATE_FAILED", message: error.message });
1543
+ }
1544
+ return ok(data);
1545
+ } catch (error) {
1546
+ log3.error("Error updating file reference:", error);
1547
+ return err(toApiError(error));
1548
+ }
1549
+ }
1550
+ async deleteFileReference(table_name, record_id, organisation_id, delete_file = false) {
1551
+ try {
1552
+ const refResult = await this.getFileReference(table_name, record_id, organisation_id);
1553
+ const fileRef = refResult.ok ? refResult.data : null;
1554
+ const { error } = await this.supabase.rpc("data_file_reference_delete", {
1555
+ p_table_name: table_name,
1556
+ p_record_id: record_id,
1557
+ p_organisation_id: organisation_id ?? null,
1558
+ p_delete_file: delete_file
1559
+ });
1560
+ if (error) {
1561
+ return err({ code: "DELETE_FAILED", message: error.message });
1562
+ }
1563
+ if (delete_file && fileRef) {
1564
+ await deleteFile(this.supabase, fileRef.file_path, fileRef.is_public || false);
1565
+ }
1566
+ return ok(true);
1567
+ } catch (error) {
1568
+ log3.error("Error deleting file reference:", error);
1569
+ return err(toApiError(error));
1570
+ }
1571
+ }
1572
+ async listFileReferences(table_name, record_id, organisation_id) {
1573
+ try {
1574
+ const { data, error } = await this.supabase.rpc("data_file_reference_list", {
1575
+ p_table_name: table_name,
1576
+ p_record_id: record_id,
1577
+ p_organisation_id: organisation_id ?? null
1578
+ });
1579
+ if (error) {
1580
+ return err({ code: "LIST_FAILED", message: error.message });
1581
+ }
1582
+ if (!data || data.length === 0) {
1583
+ return ok([]);
1584
+ }
1585
+ const fileReferences = data.filter((item) => item.id && item.file_path && item.file_metadata).map((item) => {
1586
+ const fileName = item.file_path.split("/").pop() || "unknown";
1587
+ const fileType = fileName.split(".").pop() || "unknown";
1588
+ return {
1589
+ id: item.id,
1590
+ table_name,
1591
+ record_id,
1592
+ file_path: item.file_path,
1593
+ file_metadata: { fileName, fileType, ...item.file_metadata || {} },
1594
+ organisation_id: organisation_id ?? null,
1595
+ app_id: item.file_metadata?.app_id ? assertAppId(item.file_metadata.app_id) : assertAppId(""),
1596
+ is_public: item.is_public ?? false,
1597
+ created_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1598
+ updated_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString()
1599
+ };
1600
+ });
1601
+ return ok(fileReferences);
1602
+ } catch (error) {
1603
+ log3.error("Error listing file references:", error);
1604
+ return err(toApiError(error));
1605
+ }
1606
+ }
1607
+ async getFileCount(table_name, record_id, organisation_id) {
1608
+ try {
1609
+ const { data, error } = await this.supabase.rpc("data_file_reference_count_get", {
1610
+ p_table_name: table_name,
1611
+ p_record_id: record_id,
1612
+ p_organisation_id: organisation_id ?? null
1613
+ });
1614
+ if (error) {
1615
+ return err({ code: "COUNT_FAILED", message: error.message });
1616
+ }
1617
+ return ok(data ?? 0);
1618
+ } catch (error) {
1619
+ log3.error("Error getting file count:", error);
1620
+ return err(toApiError(error));
1621
+ }
1622
+ }
1623
+ async getFileReferenceById(id, organisation_id) {
1624
+ try {
1625
+ const { data, error } = await this.supabase.rpc("data_file_reference_get", {
1626
+ p_file_reference_id: id,
1627
+ p_organisation_id: organisation_id ?? null
1628
+ });
1629
+ if (error) {
1630
+ return err({ code: "FETCH_FAILED", message: error.message });
1631
+ }
1632
+ if (!data || data.length === 0) {
1633
+ return ok(null);
1634
+ }
1635
+ return ok(data[0]);
1636
+ } catch (error) {
1637
+ log3.error("Error getting file reference by ID:", error);
1638
+ return err(toApiError(error));
1639
+ }
1640
+ }
1641
+ async getFilesByCategory(table_name, record_id, category, organisation_id) {
1642
+ try {
1643
+ const { data, error } = await this.supabase.rpc("data_file_reference_by_category_list", {
1644
+ p_table_name: table_name,
1645
+ p_record_id: record_id,
1646
+ p_category: category,
1647
+ p_organisation_id: organisation_id ?? null
1648
+ });
1649
+ if (error) {
1650
+ log3.error("RPC ERROR getting files by category:", { error, table_name, record_id, category });
1651
+ return err({ code: "LIST_FAILED", message: error.message });
1652
+ }
1653
+ if (!data || data.length === 0) {
1654
+ return ok([]);
1655
+ }
1656
+ const fileReferences = data.filter((item) => {
1657
+ const fileCategory = item.file_metadata?.category;
1658
+ return fileCategory === category && item.id && item.file_path && item.file_metadata;
1659
+ }).map((item) => ({
1660
+ id: item.id,
1661
+ table_name,
1662
+ record_id,
1663
+ file_path: item.file_path,
1664
+ file_metadata: {
1665
+ fileName: item.file_path.split("/").pop() || "unknown",
1666
+ fileType: item.file_path.split(".").pop() || "unknown",
1667
+ category: item.file_metadata?.category || "general_documents" /* GENERAL_DOCUMENTS */,
1668
+ ...item.file_metadata || {}
1669
+ },
1670
+ organisation_id: organisation_id ?? null,
1671
+ app_id: item.file_metadata?.app_id ? assertAppId(item.file_metadata.app_id) : assertAppId(""),
1672
+ is_public: item.is_public ?? false,
1673
+ created_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1674
+ updated_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString()
1675
+ }));
1676
+ return ok(fileReferences);
1677
+ } catch (error) {
1678
+ log3.error("Error getting files by category:", error);
1679
+ return err(toApiError(error));
1680
+ }
1681
+ }
1682
+ async uploadMultipleFiles(options, files) {
1683
+ const success = [];
1684
+ const failed = [];
1685
+ const results = [];
1686
+ for (const file of files) {
1687
+ const result = await this.createFileReference(options, file);
1688
+ if (result.ok) {
1689
+ const fileReference = result.data;
1690
+ success.push(fileReference);
1691
+ results.push({
1692
+ file,
1693
+ result: {
1694
+ file_reference: fileReference,
1695
+ file_url: fileReference.is_public ? getPublicUrl(this.supabase, fileReference.file_path, true) : ""
1696
+ }
1697
+ });
1698
+ } else {
1699
+ failed.push({ file, error: result.error.message });
1700
+ results.push({ file, result: null, error: result.error.message });
1701
+ }
1702
+ }
1703
+ return ok({
1704
+ success,
1705
+ failed,
1706
+ total: results.length,
1707
+ successful: success.length,
1708
+ results
1709
+ });
1710
+ }
1711
+ };
1712
+ function createFileReferenceService(supabase) {
1713
+ return new FileReferenceServiceImpl(supabase);
1714
+ }
1715
+ async function uploadFileWithReference(supabase, options, file) {
1716
+ const service = createFileReferenceService(supabase);
1717
+ const result = await service.createFileReference(options, file);
1718
+ if (!result.ok) {
1719
+ return result;
1720
+ }
1721
+ const fileReference = result.data;
1722
+ let urlString;
1723
+ if (options.is_public) {
1724
+ urlString = getPublicUrl(supabase, fileReference.file_path, true);
1725
+ } else {
1726
+ const signedResult = await getSignedUrl(supabase, fileReference.file_path, {
1727
+ appName: "file-reference",
1728
+ orgId: options.organisation_id || void 0,
1729
+ userId: options.userId || void 0,
1730
+ expiresIn: 3600
1731
+ });
1732
+ urlString = signedResult.ok ? signedResult.data.url ?? "" : "";
1733
+ }
1734
+ return ok({
1735
+ file_reference: fileReference,
1736
+ file_url: urlString,
1737
+ signed_url: options.is_public ? void 0 : urlString || void 0
1738
+ });
1739
+ }
1740
+
1741
+ // src/components/FileDisplay/useFileDisplayData.ts
1742
+ async function fetchFileDisplayDataInternal(params) {
1743
+ const { table_name, record_id, organisation_id, category, supabase } = params;
1744
+ if (!supabase) {
1745
+ return [];
1746
+ }
1747
+ let query = supabase.from("core_file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at, created_by").eq("table_name", table_name).eq("record_id", record_id);
1748
+ if (organisation_id === void 0 || organisation_id === null) {
1749
+ query = query.is("organisation_id", null);
1750
+ } else {
1751
+ query = query.eq("organisation_id", organisation_id);
1752
+ }
1753
+ if (category !== void 0 && category !== null) {
1754
+ query = query.contains("file_metadata", { category });
1755
+ }
1756
+ const { data, error } = await query.order("created_at", { ascending: false });
1757
+ if (error) {
1758
+ throw new Error(error.message ?? "Failed to fetch file references");
1759
+ }
1760
+ const rows = data ?? [];
1761
+ return rows.map(mapFileReferenceRowToFileReference);
1762
+ }
1763
+
1764
+ // src/components/FileDisplay/useFileDisplay.ts
1765
+ var authenticatedFileCache = /* @__PURE__ */ new Map();
1766
+ var MAX_CACHE_SIZE2 = 100;
1767
+ function cleanupCache() {
1768
+ const now = Date.now();
1769
+ const entries = Array.from(authenticatedFileCache.entries());
1770
+ const expiredKeys = [];
1771
+ entries.forEach(([key, value]) => {
1772
+ if (now - value.timestamp >= value.ttl) {
1773
+ expiredKeys.push(key);
1774
+ }
1775
+ });
1776
+ expiredKeys.forEach((key) => authenticatedFileCache.delete(key));
1777
+ if (authenticatedFileCache.size > MAX_CACHE_SIZE2) {
1778
+ const sorted = entries.filter(([key]) => !expiredKeys.includes(key)).sort((a, b) => a[1].timestamp - b[1].timestamp);
1779
+ const toRemove = sorted.slice(0, authenticatedFileCache.size - MAX_CACHE_SIZE2);
1780
+ toRemove.forEach(([key]) => authenticatedFileCache.delete(key));
1781
+ }
1782
+ }
1783
+ function getFileDisplayCacheKey(table_name, record_id, organisation_id, category) {
1784
+ return `file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1785
+ }
1786
+ async function tryApplyCacheHit(cacheKey, enableCache, cacheTtl, supabase, organisation_id, record_id, safeSetState, setters) {
1787
+ if (!enableCache || !supabase) return false;
1788
+ const cached = authenticatedFileCache.get(cacheKey);
1789
+ if (!cached || Date.now() - cached.timestamp >= cached.ttl) return false;
1790
+ const cachedData = cached.data;
1791
+ if (cachedData.fileReference && !cachedData.fileUrl && cachedData.fileReference.is_public === false && supabase) {
1792
+ try {
1793
+ const signedUrlResult = await getSignedUrl(supabase, cachedData.fileReference.file_path, {
1794
+ appName: "pace-core",
1795
+ orgId: organisation_id,
1796
+ userId: organisation_id ? void 0 : record_id,
1797
+ expiresIn: 3600
1798
+ });
1799
+ const regeneratedUrl = signedUrlResult.ok ? signedUrlResult.data.url : null;
1800
+ safeSetState(setters.setFileUrl, regeneratedUrl);
1801
+ safeSetState(setters.setFileReference, cachedData.fileReference);
1802
+ safeSetState(setters.setFileReferences, cachedData.fileReferences || []);
1803
+ safeSetState(setters.setFileUrls, cachedData.fileUrls || /* @__PURE__ */ new Map());
1804
+ safeSetState(setters.setFileCount, cachedData.fileCount || 0);
1805
+ safeSetState(setters.setIsLoading, false);
1806
+ safeSetState(setters.setError, null);
1807
+ return true;
1808
+ } catch (err2) {
1809
+ logger.warn("useFileDisplay", "Failed to regenerate signed URL from cache, falling back to fetch:", err2);
1810
+ }
1811
+ }
1812
+ safeSetState(setters.setFileUrl, cachedData.fileUrl || null);
1813
+ safeSetState(setters.setFileReference, cachedData.fileReference || null);
1814
+ safeSetState(setters.setFileReferences, cachedData.fileReferences || []);
1815
+ safeSetState(setters.setFileUrls, cachedData.fileUrls || /* @__PURE__ */ new Map());
1816
+ safeSetState(setters.setFileCount, cachedData.fileCount || 0);
1817
+ safeSetState(setters.setIsLoading, false);
1818
+ safeSetState(setters.setError, null);
1819
+ return true;
1820
+ }
1821
+ async function applyFetchedFilesAndCache(files, category, table_name, record_id, organisation_id, supabase, cacheKey, enableCache, cacheTtl, safeSetState, setters) {
1822
+ safeSetState(setters.setFileReferences, files);
1823
+ safeSetState(setters.setFileCount, files.length);
1824
+ if (category && files.length > 0) {
1825
+ const firstFile = files[0];
1826
+ safeSetState(setters.setFileReference, firstFile);
1827
+ let url = null;
1828
+ if (firstFile.is_public) {
1829
+ url = getPublicUrl(supabase, firstFile.file_path, true);
1830
+ } else {
1831
+ const signedUrlResult = await getSignedUrl(supabase, firstFile.file_path, {
1832
+ appName: "pace-core",
1833
+ orgId: organisation_id,
1834
+ userId: organisation_id ? void 0 : record_id,
1835
+ expiresIn: 3600
1836
+ });
1837
+ url = signedUrlResult.ok ? signedUrlResult.data.url : null;
1838
+ if (!url) {
1839
+ logger.warn("useFileDisplay", "Failed to generate signed URL for file:", {
1840
+ file_path: firstFile.file_path,
1841
+ record_id,
1842
+ table_name
1843
+ });
1844
+ }
1845
+ }
1846
+ safeSetState(setters.setFileUrl, url);
1847
+ } else {
1848
+ const urlResult = await generateFileUrlsBatch(supabase, files, {
1849
+ appName: "pace-core",
1850
+ orgId: organisation_id,
1851
+ userId: organisation_id ? void 0 : record_id,
1852
+ expiresIn: 3600
1853
+ });
1854
+ const urlMap = urlResult.ok ? urlResult.data : /* @__PURE__ */ new Map();
1855
+ safeSetState(setters.setFileUrls, urlMap);
1856
+ safeSetState(setters.setFileReference, null);
1857
+ safeSetState(setters.setFileUrl, null);
1858
+ }
1859
+ if (enableCache) {
1860
+ const cacheData = {
1861
+ fileUrl: null,
1862
+ fileReference: category && files.length > 0 ? files[0] : null,
1863
+ fileReferences: files,
1864
+ fileUrls: /* @__PURE__ */ new Map(),
1865
+ fileCount: files.length
1866
+ };
1867
+ if (category && files.length > 0) {
1868
+ const firstFile = files[0];
1869
+ cacheData.fileUrl = firstFile.is_public ? getPublicUrl(supabase, firstFile.file_path, true) : null;
1870
+ } else {
1871
+ const urlMap = /* @__PURE__ */ new Map();
1872
+ for (const fileRef of files) {
1873
+ if (fileRef.is_public) {
1874
+ const url = getPublicUrl(supabase, fileRef.file_path, true);
1875
+ if (url) urlMap.set(fileRef.id, url);
1876
+ }
1877
+ }
1878
+ cacheData.fileUrls = urlMap;
1879
+ }
1880
+ authenticatedFileCache.set(cacheKey, {
1881
+ data: cacheData,
1882
+ timestamp: Date.now(),
1883
+ ttl: cacheTtl
1884
+ });
1885
+ cleanupCache();
1886
+ }
1887
+ }
1888
+ function useFileDisplay(table_name, record_id, organisation_id, category, options) {
1889
+ const {
1890
+ cacheTtl = 30 * 60 * 1e3,
1891
+ // 30 minutes
1892
+ enableCache = true,
1893
+ supabase
1894
+ } = options;
1895
+ const [fileUrl, setFileUrl] = useState(null);
1896
+ const [fileReference, setFileReference] = useState(null);
1897
+ const [fileReferences, setFileReferences] = useState([]);
1898
+ const [fileUrls, setFileUrls] = useState(/* @__PURE__ */ new Map());
1899
+ const [fileCount, setFileCount] = useState(0);
1900
+ const [isLoading, setIsLoading] = useState(false);
1901
+ const [error, setError] = useState(null);
1902
+ const isMountedRef = useRef(true);
1903
+ const safeSetState = (setter, value) => {
1904
+ if (isMountedRef.current) {
1905
+ setter(value);
1906
+ }
1907
+ };
1908
+ const fetchFiles = useCallback(async () => {
1909
+ if (!table_name || !record_id || !supabase) {
1910
+ safeSetState(setFileUrl, null);
1911
+ safeSetState(setFileReference, null);
1912
+ safeSetState(setFileReferences, []);
1913
+ safeSetState(setFileUrls, /* @__PURE__ */ new Map());
1914
+ safeSetState(setFileCount, 0);
1915
+ safeSetState(setIsLoading, false);
1916
+ return;
1917
+ }
1918
+ if (organisation_id) {
1919
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1920
+ if (!uuidRegex.test(organisation_id)) {
1921
+ logger.warn("useFileDisplay", "Invalid organisationId format (not a valid UUID):", organisation_id);
1922
+ }
1923
+ }
1924
+ safeSetState(setIsLoading, true);
1925
+ safeSetState(setError, null);
1926
+ const cacheKey = getFileDisplayCacheKey(table_name, record_id, organisation_id, category);
1927
+ const applied = await tryApplyCacheHit(
1928
+ cacheKey,
1929
+ enableCache,
1930
+ cacheTtl,
1931
+ supabase,
1932
+ organisation_id,
1933
+ record_id,
1934
+ safeSetState,
1935
+ {
1936
+ setFileUrl,
1937
+ setFileReference,
1938
+ setFileReferences,
1939
+ setFileUrls,
1940
+ setFileCount,
1941
+ setIsLoading,
1942
+ setError
1943
+ }
1944
+ );
1945
+ if (applied) return;
1946
+ try {
1947
+ const files = await fetchFileDisplayDataInternal({
1948
+ table_name,
1949
+ record_id,
1950
+ organisation_id,
1951
+ category,
1952
+ supabase
1953
+ });
1954
+ if (files.length === 0) {
1955
+ safeSetState(setFileUrl, null);
1956
+ safeSetState(setFileReference, null);
1957
+ safeSetState(setFileReferences, []);
1958
+ safeSetState(setFileUrls, /* @__PURE__ */ new Map());
1959
+ safeSetState(setFileCount, 0);
1960
+ if (enableCache) {
1961
+ authenticatedFileCache.set(cacheKey, {
1962
+ data: { fileUrl: null, fileReference: null, fileReferences: [], fileUrls: /* @__PURE__ */ new Map(), fileCount: 0 },
1963
+ timestamp: Date.now(),
1964
+ ttl: cacheTtl
1965
+ });
1966
+ cleanupCache();
1967
+ }
1968
+ return;
1969
+ }
1970
+ await applyFetchedFilesAndCache(
1971
+ files,
1972
+ category,
1973
+ table_name,
1974
+ record_id,
1975
+ organisation_id,
1976
+ supabase,
1977
+ cacheKey,
1978
+ enableCache,
1979
+ cacheTtl,
1980
+ safeSetState,
1981
+ { setFileUrl, setFileReference, setFileReferences, setFileUrls, setFileCount }
1982
+ );
1983
+ } catch (err2) {
1984
+ logger.error("useFileDisplay", "Error fetching files:", err2);
1985
+ const error2 = err2 instanceof Error ? err2 : new Error("Unknown error occurred");
1986
+ safeSetState(setError, error2);
1987
+ safeSetState(setFileUrl, null);
1988
+ safeSetState(setFileReference, null);
1989
+ safeSetState(setFileReferences, []);
1990
+ safeSetState(setFileUrls, /* @__PURE__ */ new Map());
1991
+ safeSetState(setFileCount, 0);
1992
+ } finally {
1993
+ safeSetState(setIsLoading, false);
1994
+ }
1995
+ }, [table_name, record_id, organisation_id, category, supabase, cacheTtl, enableCache]);
1996
+ useEffect(() => {
1997
+ isMountedRef.current = true;
1998
+ if (table_name && record_id && supabase) {
1999
+ fetchFiles().catch((err2) => {
2000
+ if (isMountedRef.current) {
2001
+ safeSetState(setError, err2 instanceof Error ? err2 : new Error("Unknown error"));
2002
+ }
2003
+ });
2004
+ } else {
2005
+ safeSetState(setFileUrl, null);
2006
+ safeSetState(setFileReference, null);
2007
+ safeSetState(setFileReferences, []);
2008
+ safeSetState(setFileUrls, /* @__PURE__ */ new Map());
2009
+ safeSetState(setFileCount, 0);
2010
+ safeSetState(setIsLoading, false);
2011
+ safeSetState(setError, null);
2012
+ }
2013
+ return () => {
2014
+ isMountedRef.current = false;
2015
+ };
2016
+ }, [table_name, record_id, organisation_id, supabase]);
2017
+ const refetch = useCallback(async () => {
2018
+ if (!table_name || !record_id || !supabase) return;
2019
+ if (enableCache) {
2020
+ authenticatedFileCache.delete(getFileDisplayCacheKey(table_name, record_id, organisation_id, category));
2021
+ }
2022
+ await fetchFiles();
2023
+ }, [fetchFiles, table_name, record_id, organisation_id, category, supabase, enableCache]);
2024
+ return {
2025
+ fileUrl,
2026
+ fileReference,
2027
+ fileReferences,
2028
+ fileUrls,
2029
+ fileCount,
2030
+ isLoading,
2031
+ error,
2032
+ refetch
2033
+ };
2034
+ }
2035
+ function clearFileDisplayCache() {
2036
+ for (const [key] of authenticatedFileCache) {
2037
+ if (key.startsWith("file_")) {
2038
+ authenticatedFileCache.delete(key);
2039
+ }
2040
+ }
2041
+ }
2042
+ function getFileDisplayCacheStats() {
2043
+ const keys = Array.from(authenticatedFileCache.keys()).filter((key) => key.startsWith("file_"));
2044
+ return {
2045
+ size: keys.length,
2046
+ keys
2047
+ };
2048
+ }
2049
+ function invalidateFileDisplayCache(table_name, record_id, organisation_id, category) {
2050
+ const orgId = organisation_id ?? void 0;
2051
+ authenticatedFileCache.delete(getFileDisplayCacheKey(table_name, record_id, orgId, category));
2052
+ if (category) {
2053
+ authenticatedFileCache.delete(getFileDisplayCacheKey(table_name, record_id, orgId, void 0));
2054
+ }
2055
+ }
2056
+ var log4 = createLogger("useEventTheme");
2057
+ function useEventTheme(event) {
2058
+ const location = useLocation();
2059
+ const eventServiceContext = useContext(EventServiceContext);
2060
+ const eventService = eventServiceContext?.eventService ?? null;
2061
+ useEffect(() => {
2062
+ if (event !== void 0 || !eventService) return;
2063
+ const applyThemeFromService = () => {
2064
+ const isOnLoginRoute = location.pathname === "/login" || location.pathname.startsWith("/login/");
2065
+ if (isOnLoginRoute) {
2066
+ clearPalette();
2067
+ return;
2068
+ }
2069
+ const current = eventService.getSelectedEvent();
2070
+ if (!current?.event_colours) {
2071
+ clearPalette();
2072
+ return;
2073
+ }
2074
+ const normalized = parseAndNormalizeEventColours(current.event_colours);
2075
+ if (normalized) {
2076
+ try {
2077
+ applyPalette(normalized, current.event_name ?? "");
2078
+ } catch (err2) {
2079
+ log4.error("Failed to apply event palette (subscription):", err2);
2080
+ }
2081
+ } else {
2082
+ clearPalette();
2083
+ }
2084
+ };
2085
+ applyThemeFromService();
2086
+ const unsubscribe = eventService.subscribe(applyThemeFromService);
2087
+ return () => {
2088
+ unsubscribe();
2089
+ };
2090
+ }, [event, eventService, location.pathname]);
2091
+ const eventsContextSelectedEvent = eventService?.getSelectedEvent() ?? null;
2092
+ const selectedEvent = event !== void 0 ? event : eventsContextSelectedEvent;
2093
+ useEffect(() => {
2094
+ const isOnLoginRoute = location.pathname === "/login" || location.pathname.startsWith("/login");
2095
+ if (isOnLoginRoute) {
2096
+ clearPalette();
2097
+ return;
2098
+ }
2099
+ if (event === void 0) {
2100
+ return;
2101
+ }
2102
+ if (!selectedEvent) {
2103
+ clearPalette();
2104
+ return;
2105
+ }
2106
+ const eventColours = selectedEvent.event_colours;
2107
+ const normalized = parseAndNormalizeEventColours(eventColours);
2108
+ if (!normalized) {
2109
+ clearPalette();
2110
+ return;
2111
+ }
2112
+ try {
2113
+ applyPalette(normalized, selectedEvent.event_name ?? "");
2114
+ } catch (error) {
2115
+ log4.error("Failed to apply event palette:", error);
2116
+ }
2117
+ }, [selectedEvent, location.pathname, event]);
2118
+ }
2119
+ function usePreventTabReload(options = {}) {
2120
+ const { enabled = true, gracePeriodMs = 2e3 } = options;
2121
+ const isRestoringFromCacheRef = useRef(false);
2122
+ const gracePeriodTimeoutRef = useRef(null);
2123
+ useEffect(() => {
2124
+ if (!enabled || typeof window === "undefined") return;
2125
+ const handlePageShow = (event) => {
2126
+ if (event.persisted) {
2127
+ isRestoringFromCacheRef.current = true;
2128
+ if (gracePeriodTimeoutRef.current) {
2129
+ clearTimeout(gracePeriodTimeoutRef.current);
2130
+ }
2131
+ gracePeriodTimeoutRef.current = setTimeout(() => {
2132
+ isRestoringFromCacheRef.current = false;
2133
+ }, gracePeriodMs);
2134
+ }
2135
+ };
2136
+ const handleVisibilityChange = () => {
2137
+ if (!document.hidden) {
2138
+ isRestoringFromCacheRef.current = true;
2139
+ if (gracePeriodTimeoutRef.current) {
2140
+ clearTimeout(gracePeriodTimeoutRef.current);
2141
+ }
2142
+ gracePeriodTimeoutRef.current = setTimeout(() => {
2143
+ isRestoringFromCacheRef.current = false;
2144
+ }, gracePeriodMs);
2145
+ }
2146
+ };
2147
+ window.addEventListener("pageshow", handlePageShow);
2148
+ document.addEventListener("visibilitychange", handleVisibilityChange);
2149
+ return () => {
2150
+ window.removeEventListener("pageshow", handlePageShow);
2151
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
2152
+ if (gracePeriodTimeoutRef.current) {
2153
+ clearTimeout(gracePeriodTimeoutRef.current);
2154
+ }
2155
+ };
2156
+ }, [enabled, gracePeriodMs]);
2157
+ }
2158
+
2159
+ export { APP_PATH_MAPPING, DEFAULT_FILE_SIZE_LIMIT, FILE_SIZE_LIMITS, STORAGE_CONFIG, archiveFile, cleanupQueryCache, clearFileDisplayCache, clearPublicFileDisplayCache, createFileReferenceService, deleteFile, downloadFile, extractFileMetadata, generateFilePath, generateFileUrlsBatch, generateUniqueFileName, getBucketName, getFileDisplayCacheStats, getFileSizeLimit, getPublicFileDisplayCacheStats, getPublicUrl, getSignedUrl, invalidateFileDisplayCache, listFiles, queryCacheHelpers, uploadFile, uploadFileWithReference, useAddressAutocomplete, useDebounce, useEventTheme, useFileDisplay, usePreventTabReload, usePublicFileDisplay, useQueryCache, validateFileSize };