@jmruthers/pace-core 0.5.189 → 0.5.191

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 (438) hide show
  1. package/core-usage-manifest.json +0 -4
  2. package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
  3. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  4. package/dist/{DataTable-GUFUNZ3N.js → DataTable-WKRZD47S.js} +8 -8
  5. package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +84 -25
  6. package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
  7. package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-FTSG5XH7.js} +4 -2
  8. package/dist/{api-YP7XD5L6.js → api-IHKALJZD.js} +4 -2
  9. package/dist/{chunk-VGZZXKBR.js → chunk-6LTQQAT6.js} +351 -157
  10. package/dist/chunk-6LTQQAT6.js.map +1 -0
  11. package/dist/{chunk-MX64ZF6I.js → chunk-6TQDD426.js} +15 -15
  12. package/dist/chunk-6TQDD426.js.map +1 -0
  13. package/dist/{chunk-YHCN776L.js → chunk-G37KK66H.js} +2 -75
  14. package/dist/chunk-G37KK66H.js.map +1 -0
  15. package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
  16. package/dist/chunk-HW3OVDUF.js.map +1 -0
  17. package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
  18. package/dist/chunk-I7PSE6JW.js.map +1 -0
  19. package/dist/{chunk-IM4QE42D.js → chunk-LOMZXPSN.js} +141 -326
  20. package/dist/chunk-LOMZXPSN.js.map +1 -0
  21. package/dist/chunk-OETXORNB.js +614 -0
  22. package/dist/chunk-OETXORNB.js.map +1 -0
  23. package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
  24. package/dist/{chunk-HEHYGYOX.js → chunk-ROXMHMY2.js} +403 -46
  25. package/dist/chunk-ROXMHMY2.js.map +1 -0
  26. package/dist/{chunk-2UUZZJFT.js → chunk-ULHIJK66.js} +228 -177
  27. package/dist/{chunk-2UUZZJFT.js.map → chunk-ULHIJK66.js.map} +1 -1
  28. package/dist/{chunk-YGPFYGA6.js → chunk-VKB2CO4Z.js} +838 -503
  29. package/dist/chunk-VKB2CO4Z.js.map +1 -0
  30. package/dist/{chunk-3GOZZZYH.js → chunk-VRGWKHDB.js} +238 -301
  31. package/dist/chunk-VRGWKHDB.js.map +1 -0
  32. package/dist/{chunk-UCQSRW7Z.js → chunk-XNYQOL3Z.js} +431 -384
  33. package/dist/chunk-XNYQOL3Z.js.map +1 -0
  34. package/dist/{chunk-DDM4CCYT.js → chunk-XYXSXPUK.js} +79 -59
  35. package/dist/chunk-XYXSXPUK.js.map +1 -0
  36. package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
  37. package/dist/chunk-ZSAAAMVR.js.map +1 -0
  38. package/dist/components.d.ts +5 -6
  39. package/dist/components.js +19 -19
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  42. package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
  43. package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
  44. package/dist/hooks.d.ts +20 -15
  45. package/dist/hooks.js +14 -8
  46. package/dist/hooks.js.map +1 -1
  47. package/dist/index.d.ts +17 -15
  48. package/dist/index.js +86 -81
  49. package/dist/index.js.map +1 -1
  50. package/dist/providers.d.ts +3 -3
  51. package/dist/providers.js +3 -1
  52. package/dist/rbac/index.d.ts +77 -13
  53. package/dist/rbac/index.js +12 -9
  54. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  55. package/dist/types.d.ts +3 -3
  56. package/dist/types.js +1 -1
  57. package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +17 -10
  58. package/dist/utils.d.ts +8 -8
  59. package/dist/utils.js +16 -16
  60. package/docs/README.md +2 -2
  61. package/docs/api/classes/ColumnFactory.md +1 -1
  62. package/docs/api/classes/ErrorBoundary.md +1 -1
  63. package/docs/api/classes/InvalidScopeError.md +2 -2
  64. package/docs/api/classes/Logger.md +1 -1
  65. package/docs/api/classes/MissingUserContextError.md +2 -2
  66. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  67. package/docs/api/classes/PermissionDeniedError.md +1 -1
  68. package/docs/api/classes/RBACAuditManager.md +2 -2
  69. package/docs/api/classes/RBACCache.md +1 -1
  70. package/docs/api/classes/RBACEngine.md +5 -5
  71. package/docs/api/classes/RBACError.md +1 -1
  72. package/docs/api/classes/RBACNotInitializedError.md +2 -2
  73. package/docs/api/classes/SecureSupabaseClient.md +25 -20
  74. package/docs/api/classes/StorageUtils.md +7 -4
  75. package/docs/api/enums/FileCategory.md +1 -1
  76. package/docs/api/enums/LogLevel.md +1 -1
  77. package/docs/api/enums/RBACErrorCode.md +1 -1
  78. package/docs/api/enums/RPCFunction.md +1 -1
  79. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  80. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +1 -1
  82. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  83. package/docs/api/interfaces/AvatarProps.md +1 -1
  84. package/docs/api/interfaces/BadgeProps.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CalendarProps.md +20 -6
  87. package/docs/api/interfaces/CardProps.md +1 -1
  88. package/docs/api/interfaces/ColorPalette.md +1 -1
  89. package/docs/api/interfaces/ColorShade.md +1 -1
  90. package/docs/api/interfaces/ComplianceResult.md +1 -1
  91. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  92. package/docs/api/interfaces/DataRecord.md +1 -1
  93. package/docs/api/interfaces/DataTableAction.md +1 -1
  94. package/docs/api/interfaces/DataTableColumn.md +1 -1
  95. package/docs/api/interfaces/DataTableProps.md +1 -1
  96. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  97. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  98. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  99. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  100. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  101. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  102. package/docs/api/interfaces/ExportColumn.md +1 -1
  103. package/docs/api/interfaces/ExportOptions.md +1 -1
  104. package/docs/api/interfaces/FileDisplayProps.md +62 -16
  105. package/docs/api/interfaces/FileMetadata.md +1 -1
  106. package/docs/api/interfaces/FileReference.md +2 -2
  107. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  108. package/docs/api/interfaces/FileUploadOptions.md +26 -12
  109. package/docs/api/interfaces/FileUploadProps.md +30 -19
  110. package/docs/api/interfaces/FooterProps.md +1 -1
  111. package/docs/api/interfaces/FormFieldProps.md +1 -1
  112. package/docs/api/interfaces/FormProps.md +1 -1
  113. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  114. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  115. package/docs/api/interfaces/InputProps.md +1 -1
  116. package/docs/api/interfaces/LabelProps.md +1 -1
  117. package/docs/api/interfaces/LoggerConfig.md +1 -1
  118. package/docs/api/interfaces/LoginFormProps.md +1 -1
  119. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  120. package/docs/api/interfaces/NavigationContextType.md +9 -9
  121. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  122. package/docs/api/interfaces/NavigationItem.md +1 -1
  123. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  124. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  125. package/docs/api/interfaces/Organisation.md +1 -1
  126. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  127. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  128. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  129. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  130. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  131. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  132. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  133. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  134. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  135. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  136. package/docs/api/interfaces/PaletteData.md +1 -1
  137. package/docs/api/interfaces/ParsedAddress.md +2 -2
  138. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  139. package/docs/api/interfaces/ProgressProps.md +3 -11
  140. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  141. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  142. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  143. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  144. package/docs/api/interfaces/QuickFix.md +1 -1
  145. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  146. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  147. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  148. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  149. package/docs/api/interfaces/RBACConfig.md +2 -2
  150. package/docs/api/interfaces/RBACContext.md +1 -1
  151. package/docs/api/interfaces/RBACLogger.md +1 -1
  152. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  153. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  154. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  155. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  156. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  157. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  158. package/docs/api/interfaces/RBACResult.md +1 -1
  159. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  160. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  161. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  162. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  163. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  164. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  165. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  166. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  167. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  168. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  169. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  170. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  171. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  172. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  173. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  174. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  175. package/docs/api/interfaces/RouteConfig.md +10 -10
  176. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  177. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  178. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  179. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  180. package/docs/api/interfaces/SetupIssue.md +1 -1
  181. package/docs/api/interfaces/StorageConfig.md +4 -4
  182. package/docs/api/interfaces/StorageFileInfo.md +7 -7
  183. package/docs/api/interfaces/StorageFileMetadata.md +25 -14
  184. package/docs/api/interfaces/StorageListOptions.md +22 -9
  185. package/docs/api/interfaces/StorageListResult.md +4 -4
  186. package/docs/api/interfaces/StorageUploadOptions.md +21 -8
  187. package/docs/api/interfaces/StorageUploadResult.md +6 -6
  188. package/docs/api/interfaces/StorageUrlOptions.md +19 -6
  189. package/docs/api/interfaces/StyleImport.md +1 -1
  190. package/docs/api/interfaces/SwitchProps.md +1 -1
  191. package/docs/api/interfaces/TabsContentProps.md +1 -1
  192. package/docs/api/interfaces/TabsListProps.md +1 -1
  193. package/docs/api/interfaces/TabsProps.md +1 -1
  194. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  195. package/docs/api/interfaces/TextareaProps.md +1 -1
  196. package/docs/api/interfaces/ToastActionElement.md +1 -1
  197. package/docs/api/interfaces/ToastProps.md +1 -1
  198. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  199. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  200. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  201. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  202. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  203. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  204. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  205. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  206. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  207. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  208. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  209. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  210. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  211. package/docs/api/interfaces/UseResolvedScopeOptions.md +5 -5
  212. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  213. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  214. package/docs/api/interfaces/UserEventAccess.md +11 -11
  215. package/docs/api/interfaces/UserMenuProps.md +1 -1
  216. package/docs/api/interfaces/UserProfile.md +1 -1
  217. package/docs/api/modules.md +165 -106
  218. package/docs/api-reference/components.md +15 -7
  219. package/docs/api-reference/providers.md +2 -2
  220. package/docs/api-reference/rpc-functions.md +1 -0
  221. package/docs/best-practices/README.md +1 -1
  222. package/docs/best-practices/deployment.md +8 -8
  223. package/docs/getting-started/examples/README.md +2 -2
  224. package/docs/getting-started/installation-guide.md +4 -4
  225. package/docs/getting-started/quick-start.md +3 -3
  226. package/docs/migration/MIGRATION_GUIDE.md +3 -3
  227. package/docs/migration/README.md +18 -0
  228. package/docs/migration/database-changes-december-2025.md +767 -0
  229. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  230. package/docs/rbac/compliance/compliance-guide.md +2 -2
  231. package/docs/rbac/event-based-apps.md +2 -2
  232. package/docs/rbac/getting-started.md +2 -2
  233. package/docs/rbac/quick-start.md +2 -2
  234. package/docs/security/README.md +4 -4
  235. package/docs/standards/07-rbac-and-rls-standard.md +430 -7
  236. package/docs/troubleshooting/README.md +2 -2
  237. package/docs/troubleshooting/migration.md +3 -3
  238. package/package.json +1 -3
  239. package/scripts/check-pace-core-compliance.cjs +1 -1
  240. package/scripts/check-pace-core-compliance.js +1 -1
  241. package/src/__tests__/fixtures/supabase.ts +301 -0
  242. package/src/__tests__/public-recipe-view.test.ts +19 -19
  243. package/src/__tests__/rls-policies.test.ts +210 -74
  244. package/src/components/AddressField/AddressField.test.tsx +42 -0
  245. package/src/components/AddressField/AddressField.tsx +71 -60
  246. package/src/components/AddressField/README.md +7 -6
  247. package/src/components/Alert/Alert.test.tsx +50 -10
  248. package/src/components/Alert/Alert.tsx +5 -3
  249. package/src/components/Avatar/Avatar.test.tsx +95 -43
  250. package/src/components/Avatar/Avatar.tsx +16 -16
  251. package/src/components/Button/Button.test.tsx +2 -1
  252. package/src/components/Button/Button.tsx +3 -3
  253. package/src/components/Calendar/Calendar.test.tsx +53 -37
  254. package/src/components/Calendar/Calendar.tsx +409 -82
  255. package/src/components/Card/Card.test.tsx +7 -4
  256. package/src/components/Card/Card.tsx +3 -6
  257. package/src/components/Checkbox/Checkbox.tsx +2 -2
  258. package/src/components/DataTable/components/ActionButtons.tsx +5 -5
  259. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  260. package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
  261. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
  262. package/src/components/DataTable/components/DataTableBody.tsx +12 -12
  263. package/src/components/DataTable/components/DataTableCore.tsx +3 -3
  264. package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
  265. package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
  266. package/src/components/DataTable/components/EditableRow.tsx +2 -2
  267. package/src/components/DataTable/components/EmptyState.tsx +3 -3
  268. package/src/components/DataTable/components/GroupHeader.tsx +2 -2
  269. package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
  270. package/src/components/DataTable/components/ImportModal.tsx +4 -4
  271. package/src/components/DataTable/components/LoadingState.tsx +1 -1
  272. package/src/components/DataTable/components/PaginationControls.tsx +11 -11
  273. package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
  274. package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
  275. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
  276. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
  277. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
  278. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
  279. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
  280. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
  281. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
  282. package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
  284. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
  285. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
  286. package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
  287. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
  288. package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
  289. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
  290. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
  291. package/src/components/Dialog/Dialog.tsx +2 -2
  292. package/src/components/EventSelector/EventSelector.tsx +7 -7
  293. package/src/components/FileDisplay/FileDisplay.tsx +291 -179
  294. package/src/components/FileUpload/FileUpload.tsx +7 -4
  295. package/src/components/Header/Header.test.tsx +28 -0
  296. package/src/components/Header/Header.tsx +22 -9
  297. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
  298. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
  299. package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
  301. package/src/components/OrganisationSelector/OrganisationSelector.tsx +42 -22
  302. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
  303. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
  304. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
  305. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
  306. package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
  307. package/src/components/PaceAppLayout/test-setup.tsx +1 -0
  308. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
  309. package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
  310. package/src/components/Progress/Progress.test.tsx +18 -19
  311. package/src/components/Progress/Progress.tsx +31 -32
  312. package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
  313. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
  314. package/src/components/Select/Select.test.tsx +4 -1
  315. package/src/components/Select/Select.tsx +65 -20
  316. package/src/components/Switch/Switch.test.tsx +2 -1
  317. package/src/components/Switch/Switch.tsx +1 -1
  318. package/src/components/Toast/Toast.tsx +1 -1
  319. package/src/components/Tooltip/Tooltip.test.tsx +8 -2
  320. package/src/components/UserMenu/UserMenu.tsx +3 -3
  321. package/src/eslint-rules/pace-core-compliance.cjs +0 -2
  322. package/src/eslint-rules/pace-core-compliance.js +0 -2
  323. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
  324. package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
  325. package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
  326. package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
  327. package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
  328. package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
  329. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -1
  330. package/src/hooks/__tests__/usePublicEvent.test.ts +608 -0
  331. package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
  332. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +67 -24
  333. package/src/hooks/index.ts +1 -1
  334. package/src/hooks/public/usePublicEvent.ts +10 -10
  335. package/src/hooks/public/usePublicFileDisplay.ts +173 -87
  336. package/src/hooks/useAppConfig.ts +24 -5
  337. package/src/hooks/useFileDisplay.ts +298 -36
  338. package/src/hooks/useFileReference.ts +56 -11
  339. package/src/hooks/useFileUrl.ts +1 -1
  340. package/src/hooks/useInactivityTracker.ts +16 -7
  341. package/src/hooks/usePermissionCache.test.ts +85 -8
  342. package/src/hooks/useQueryCache.ts +27 -6
  343. package/src/hooks/useSecureDataAccess.test.ts +87 -42
  344. package/src/hooks/useSecureDataAccess.ts +95 -48
  345. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  346. package/src/providers/services/EventServiceProvider.tsx +37 -17
  347. package/src/providers/services/InactivityServiceProvider.tsx +4 -4
  348. package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
  349. package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
  350. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
  351. package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
  352. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
  353. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
  354. package/src/rbac/api.ts +240 -36
  355. package/src/rbac/cache-invalidation.ts +21 -7
  356. package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
  357. package/src/rbac/components/NavigationGuard.tsx +23 -63
  358. package/src/rbac/components/NavigationProvider.test.tsx +52 -23
  359. package/src/rbac/components/NavigationProvider.tsx +13 -11
  360. package/src/rbac/components/PagePermissionGuard.tsx +77 -203
  361. package/src/rbac/components/PagePermissionProvider.tsx +13 -11
  362. package/src/rbac/components/PermissionEnforcer.tsx +24 -62
  363. package/src/rbac/components/RoleBasedRouter.tsx +14 -12
  364. package/src/rbac/components/SecureDataProvider.tsx +13 -11
  365. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
  366. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
  367. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
  368. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
  369. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
  370. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
  371. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
  372. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
  373. package/src/rbac/engine.ts +4 -2
  374. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
  375. package/src/rbac/hooks/index.ts +3 -0
  376. package/src/rbac/hooks/useCan.test.ts +101 -53
  377. package/src/rbac/hooks/usePermissions.ts +108 -41
  378. package/src/rbac/hooks/useRBAC.test.ts +11 -3
  379. package/src/rbac/hooks/useRBAC.ts +83 -40
  380. package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
  381. package/src/rbac/hooks/useResolvedScope.ts +128 -70
  382. package/src/rbac/hooks/useSecureSupabase.ts +36 -19
  383. package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
  384. package/src/rbac/request-deduplication.ts +1 -1
  385. package/src/rbac/secureClient.ts +72 -12
  386. package/src/rbac/security.ts +29 -23
  387. package/src/rbac/types.ts +10 -0
  388. package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
  389. package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
  390. package/src/rbac/utils/__tests__/eventContext.test.ts +8 -3
  391. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +74 -12
  392. package/src/rbac/utils/contextValidator.ts +288 -0
  393. package/src/rbac/utils/eventContext.ts +52 -3
  394. package/src/services/AuthService.ts +37 -8
  395. package/src/services/EventService.ts +165 -21
  396. package/src/services/OrganisationService.ts +125 -137
  397. package/src/services/__tests__/EventService.test.ts +26 -21
  398. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  399. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  400. package/src/types/database.generated.ts +166 -201
  401. package/src/types/file-reference.ts +13 -10
  402. package/src/types/supabase.ts +2 -2
  403. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  404. package/src/utils/app/appNameResolver.test.ts +346 -73
  405. package/src/utils/context/superAdminOverride.ts +58 -0
  406. package/src/utils/file-reference/index.ts +65 -37
  407. package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
  408. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  409. package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
  410. package/src/utils/google-places/types.ts +1 -1
  411. package/src/utils/request-deduplication.ts +4 -4
  412. package/src/utils/security/secureDataAccess.test.ts +1 -1
  413. package/src/utils/security/secureDataAccess.ts +7 -4
  414. package/src/utils/storage/README.md +1 -1
  415. package/src/utils/storage/helpers.test.ts +1 -1
  416. package/src/utils/storage/helpers.ts +38 -19
  417. package/src/utils/storage/types.ts +15 -8
  418. package/src/utils/validation/__tests__/csrf.test.ts +105 -0
  419. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
  420. package/src/vite-env.d.ts +2 -2
  421. package/dist/chunk-3GOZZZYH.js.map +0 -1
  422. package/dist/chunk-DDM4CCYT.js.map +0 -1
  423. package/dist/chunk-E7UAOUMY.js +0 -75
  424. package/dist/chunk-E7UAOUMY.js.map +0 -1
  425. package/dist/chunk-F2IMUDXZ.js.map +0 -1
  426. package/dist/chunk-HEHYGYOX.js.map +0 -1
  427. package/dist/chunk-IM4QE42D.js.map +0 -1
  428. package/dist/chunk-MX64ZF6I.js.map +0 -1
  429. package/dist/chunk-SAUPYVLF.js.map +0 -1
  430. package/dist/chunk-THRPYOFK.js.map +0 -1
  431. package/dist/chunk-UCQSRW7Z.js.map +0 -1
  432. package/dist/chunk-VGZZXKBR.js.map +0 -1
  433. package/dist/chunk-YGPFYGA6.js.map +0 -1
  434. package/dist/chunk-YHCN776L.js.map +0 -1
  435. /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-WKRZD47S.js.map} +0 -0
  436. /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
  437. /package/dist/{api-YP7XD5L6.js.map → api-IHKALJZD.js.map} +0 -0
  438. /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
@@ -18,33 +18,37 @@ import { createLogger } from '../core/logger';
18
18
  const log = createLogger('StorageHelpers');
19
19
 
20
20
  /**
21
- * Generate a file path based on organization-first structure
21
+ * Generate a file path based on organization-first or user-first structure
22
+ * - If orgId is provided: {orgId}/{folder}/filename
23
+ * - If userId is provided (and orgId is not): users/{userId}/{folder}/filename
22
24
  */
23
25
  export function generateFilePath(options: StorageUploadOptions, fileName: string): string {
24
- const { orgId, isPublic = false, customPath } = options;
26
+ const { orgId, userId, isPublic = false, customPath } = options;
25
27
 
26
-
27
- // Validate required orgId
28
- if (!orgId) {
29
- throw new Error('orgId is required for file path generation');
28
+ // Validate that either orgId or userId is provided
29
+ if (!orgId && !userId) {
30
+ throw new Error('Either orgId or userId is required for file path generation');
30
31
  }
31
32
 
33
+ // Determine base path: organisation-based or user-based
34
+ const basePath = orgId ? orgId : `users/${userId}`;
35
+
32
36
  if (isPublic) {
33
- // Public files go to {orgId}/{folder}/filename
37
+ // Public files go to {basePath}/{folder}/filename
34
38
  if (customPath) {
35
- return `${orgId}/${customPath}/${fileName}`;
39
+ return `${basePath}/${customPath}/${fileName}`;
36
40
  }
37
- return `${orgId}/public/${fileName}`;
41
+ return `${basePath}/public/${fileName}`;
38
42
  }
39
43
 
40
- // Organization-first structure: {orgId}/{folder}/filename
44
+ // Organization-first or user-first structure: {basePath}/{folder}/filename
41
45
  if (customPath) {
42
- return `${orgId}/${customPath}/${fileName}`;
46
+ return `${basePath}/${customPath}/${fileName}`;
43
47
  }
44
48
 
45
49
  // Use customPath if available, otherwise default to files
46
50
  const pathFolder = customPath || 'files';
47
- return `${orgId}/${pathFolder}/${fileName}`;
51
+ return `${basePath}/${pathFolder}/${fileName}`;
48
52
  }
49
53
 
50
54
  /**
@@ -86,7 +90,8 @@ export async function extractFileMetadata(
86
90
  const metadata: StorageFileMetadata = {
87
91
  mimeType: file.type,
88
92
  size: file.size,
89
- orgId: options.orgId,
93
+ ...(options.orgId && { orgId: options.orgId }),
94
+ ...(options.userId && { userId: options.userId }),
90
95
  appName: options.appName || 'pace-core',
91
96
  uploadedBy,
92
97
  uploadedAt: new Date().toISOString(),
@@ -608,8 +613,14 @@ export async function listFiles(
608
613
  // Select bucket based on isPublic flag (default to private files bucket)
609
614
  const bucketName = getBucketName(options.isPublic || false);
610
615
 
611
- // Organization-first structure: {orgId}/{category}/
612
- const pathPrefix = `${options.orgId}/`;
616
+ // Validate that either orgId or userId is provided
617
+ if (!options.orgId && !options.userId) {
618
+ throw new Error('Either orgId or userId is required for listing files');
619
+ }
620
+
621
+ // Organization-first or user-first structure
622
+ const basePath = options.orgId ? options.orgId : `users/${options.userId}`;
623
+ const pathPrefix = `${basePath}/`;
613
624
  const searchPath = options.pathPrefix ? `${pathPrefix}${options.pathPrefix}` : pathPrefix;
614
625
 
615
626
  const { data, error } = await supabase.storage
@@ -634,7 +645,8 @@ export async function listFiles(
634
645
  metadata: {
635
646
  mimeType: item.metadata?.mimetype || 'application/octet-stream',
636
647
  size: item.metadata?.size || 0,
637
- orgId: options.orgId,
648
+ ...(options.orgId && { orgId: options.orgId }),
649
+ ...(options.userId && { userId: options.userId }),
638
650
  appName: options.appName,
639
651
  uploadedBy: 'unknown',
640
652
  uploadedAt: item.created_at || new Date().toISOString(),
@@ -716,13 +728,20 @@ export async function downloadFile(
716
728
  export async function archiveFile(
717
729
  supabase: SupabaseClient,
718
730
  path: string,
719
- options: { appName: string; orgId: string; isPublic?: boolean }
731
+ options: { appName: string; orgId?: string; userId?: string; isPublic?: boolean }
720
732
  ): Promise<{ success: boolean; error?: string }> {
721
733
  try {
722
734
  const bucketName = getBucketName(options.isPublic || false);
723
735
 
724
- // Generate archived path for organization-first structure
725
- const archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
736
+ // Generate archived path for organization-first or user-first structure
737
+ let archivedPath: string;
738
+ if (options.orgId) {
739
+ archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
740
+ } else if (options.userId) {
741
+ archivedPath = path.replace(`users/${options.userId}/`, `archived/users/${options.userId}/`);
742
+ } else {
743
+ throw new Error('Either orgId or userId is required for archiving files');
744
+ }
726
745
 
727
746
  // Copy file to archived location
728
747
  const { error: copyError } = await supabase.storage
@@ -5,13 +5,15 @@
5
5
  export interface StorageUploadOptions {
6
6
  /** The app name from rbac_apps */
7
7
  appName: string;
8
- /** Organisation ID for scoping */
9
- orgId: string;
8
+ /** Organisation ID for scoping (required if userId not provided) */
9
+ orgId?: string;
10
+ /** User ID for user-scoped files (required if orgId not provided) */
11
+ userId?: string;
10
12
  /** Whether the file should be publicly accessible */
11
13
  isPublic?: boolean;
12
14
  /** Optional tags for categorisation */
13
15
  tags?: string[];
14
- /** Optional custom path within the app/org structure */
16
+ /** Optional custom path within the app/org/user structure */
15
17
  customPath?: string;
16
18
  /** Optional metadata to store with the file */
17
19
  metadata?: Record<string, any>;
@@ -23,7 +25,8 @@ export interface StorageFileMetadata {
23
25
  width?: number;
24
26
  height?: number;
25
27
  hash?: string;
26
- orgId: string;
28
+ orgId?: string;
29
+ userId?: string;
27
30
  appName: string;
28
31
  uploadedBy: string;
29
32
  uploadedAt: string;
@@ -43,8 +46,10 @@ export interface StorageUploadResult {
43
46
  export interface StorageUrlOptions {
44
47
  /** The app name from rbac_apps */
45
48
  appName: string;
46
- /** Organisation ID for scoping */
47
- orgId: string;
49
+ /** Organisation ID for scoping (required if userId not provided) */
50
+ orgId?: string;
51
+ /** User ID for user-scoped files (required if orgId not provided) */
52
+ userId?: string;
48
53
  /** Expiry time in seconds for signed URLs (default: 3600) */
49
54
  expiresIn?: number;
50
55
  }
@@ -52,8 +57,10 @@ export interface StorageUrlOptions {
52
57
  export interface StorageListOptions {
53
58
  /** The app name from rbac_apps */
54
59
  appName: string;
55
- /** Organisation ID for scoping */
56
- orgId: string;
60
+ /** Organisation ID for scoping (required if userId not provided) */
61
+ orgId?: string;
62
+ /** User ID for user-scoped files (required if orgId not provided) */
63
+ userId?: string;
57
64
  /** Optional path prefix to filter by */
58
65
  pathPrefix?: string;
59
66
  /** Optional tags to filter by */
@@ -0,0 +1,105 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import {
3
+ csrfManager,
4
+ generateCSRFToken,
5
+ validateCSRFToken,
6
+ getCSRFToken,
7
+ } from '../csrf';
8
+ import { secureStorage } from '../../security/secureStorage';
9
+
10
+ const getTokenCache = () => (csrfManager as unknown as { tokenCache: Map<string, unknown> }).tokenCache;
11
+
12
+ describe('csrf protection', () => {
13
+ beforeEach(() => {
14
+ vi.restoreAllMocks();
15
+ vi.useRealTimers();
16
+ localStorage.clear();
17
+ const cache = getTokenCache();
18
+ cache?.clear();
19
+ });
20
+
21
+ it('generates secure tokens and persists them', async () => {
22
+ const setItemSpy = vi.spyOn(secureStorage, 'setItem').mockResolvedValue();
23
+ const token = await generateCSRFToken('session-1');
24
+
25
+ expect(token).toMatch(/^[a-f0-9]{64}$/);
26
+ expect(setItemSpy).toHaveBeenCalledWith(
27
+ 'csrf_tokens',
28
+ expect.stringContaining('session-1'),
29
+ { encrypt: true, expiry: expect.any(Number) }
30
+ );
31
+
32
+ const cache = getTokenCache();
33
+ expect(cache.get(token)).toMatchObject({ sessionId: 'session-1', used: false });
34
+ });
35
+
36
+ it('validates tokens only once and marks them as used', async () => {
37
+ vi.spyOn(secureStorage, 'setItem').mockResolvedValue();
38
+ const token = await generateCSRFToken('session-2');
39
+
40
+ await expect(validateCSRFToken(token, 'session-2')).resolves.toBe(true);
41
+ await expect(validateCSRFToken(token, 'session-2')).resolves.toBe(false);
42
+
43
+ const cache = getTokenCache();
44
+ expect((cache.get(token) as any).used).toBe(true);
45
+ });
46
+
47
+ it('rejects expired tokens and persists cleanup', async () => {
48
+ const persistSpy = vi.spyOn(secureStorage, 'setItem').mockResolvedValue();
49
+ const cache = getTokenCache();
50
+
51
+ cache.set('expired-token', {
52
+ token: 'expired-token',
53
+ sessionId: 'expired-session',
54
+ timestamp: Date.now() - 31 * 60 * 1000,
55
+ used: false,
56
+ });
57
+
58
+ const result = await validateCSRFToken('expired-token', 'expired-session');
59
+ expect(result).toBe(false);
60
+ expect(cache.has('expired-token')).toBe(false);
61
+ expect(persistSpy).toHaveBeenCalled();
62
+ });
63
+
64
+ it('loads stored tokens when cache is empty and returns current token', async () => {
65
+ const now = Date.now();
66
+ vi.spyOn(secureStorage, 'getItem').mockResolvedValue(
67
+ JSON.stringify([
68
+ [
69
+ 'valid-token',
70
+ { token: 'valid-token', sessionId: 'session-load', timestamp: now, used: false },
71
+ ],
72
+ [
73
+ 'stale-token',
74
+ { token: 'stale-token', sessionId: 'session-load', timestamp: now - 40 * 60 * 1000, used: false },
75
+ ],
76
+ ])
77
+ );
78
+ const persistSpy = vi.spyOn(secureStorage, 'setItem').mockResolvedValue();
79
+
80
+ const token = await getCSRFToken('session-load');
81
+
82
+ expect(token).toBe('valid-token');
83
+ expect(persistSpy).toHaveBeenCalled();
84
+ });
85
+
86
+ it('returns false for invalid or mismatched tokens', async () => {
87
+ vi.spyOn(secureStorage, 'getItem').mockResolvedValue(null);
88
+ await expect(validateCSRFToken('unknown', 'session-x')).resolves.toBe(false);
89
+
90
+ vi.spyOn(secureStorage, 'setItem').mockResolvedValue();
91
+ const token = await generateCSRFToken('session-y');
92
+ await expect(validateCSRFToken(token, 'other-session')).resolves.toBe(false);
93
+ });
94
+
95
+ it('fails gracefully when token generation throws', async () => {
96
+ const randomSpy = vi
97
+ .spyOn(globalThis.crypto, 'getRandomValues')
98
+ .mockImplementation(() => {
99
+ throw new Error('no entropy');
100
+ });
101
+
102
+ await expect(generateCSRFToken('session-error')).rejects.toThrow('CSRF token generation failed');
103
+ expect(randomSpy).toHaveBeenCalled();
104
+ });
105
+ });
@@ -0,0 +1,92 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import {
3
+ buildSafeQueryParams,
4
+ detectSQLInjection,
5
+ escapeLikeQuery,
6
+ sanitizeFilters,
7
+ sanitizeSearchQuery,
8
+ searchQuerySchema,
9
+ sqlIdentifierSchema,
10
+ orderBySchema,
11
+ limitOffsetSchema,
12
+ } from '../sqlInjectionProtection';
13
+
14
+ describe('sqlInjectionProtection', () => {
15
+ it('sanitizes search queries by stripping dangerous characters and trimming length', () => {
16
+ const longQuery = `${'DROP TABLE users; '.repeat(40)}'%evil`;
17
+ const sanitized = sanitizeSearchQuery(longQuery);
18
+
19
+ expect(sanitized.includes('DROP')).toBe(true);
20
+ expect(sanitized).not.toContain("'");
21
+ expect(sanitized).not.toContain('%');
22
+ expect(sanitized.length).toBeLessThanOrEqual(500);
23
+ });
24
+
25
+ it('validates search query schema and transforms input', () => {
26
+ const parsed = searchQuerySchema.parse(' abc ');
27
+ expect(parsed).toBe('abc');
28
+ expect(() => searchQuerySchema.parse('SELECT * FROM users')).toThrow('Invalid characters detected in search query');
29
+ });
30
+
31
+ it('validates identifiers and ordering formats', () => {
32
+ expect(sqlIdentifierSchema.parse('valid_name')).toBe('valid_name');
33
+ expect(() => sqlIdentifierSchema.parse('SELECT')).toThrow('Identifier cannot be a reserved SQL keyword');
34
+ expect(orderBySchema.parse('created_at DESC')).toBe('created_at DESC');
35
+ expect(() => orderBySchema.parse('invalid order by')).toThrow('Invalid order by format');
36
+ });
37
+
38
+ it('validates numeric limit and offset values', () => {
39
+ expect(limitOffsetSchema.parse(25)).toBe(25);
40
+ expect(() => limitOffsetSchema.parse(-1)).toThrow('Must be non-negative');
41
+ expect(() => limitOffsetSchema.parse(10000)).toThrow('Limit too large');
42
+ });
43
+
44
+ it('escapes like queries safely', () => {
45
+ expect(escapeLikeQuery('100% match_')).toBe('100\\% match\\_');
46
+ });
47
+
48
+ it('sanitizes filters and omits invalid keys while logging', () => {
49
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
50
+ const sanitized = sanitizeFilters({
51
+ valid: 'abc',
52
+ '1invalid': 'DROP TABLE',
53
+ numbers: [1, 'two', '3;DELETE'],
54
+ malicious: "UNION SELECT password",
55
+ });
56
+
57
+ expect(sanitized.valid).toBe('abc');
58
+ expect(sanitized).not.toHaveProperty('1invalid');
59
+ expect(sanitized.malicious).toBeUndefined();
60
+ expect(sanitized.numbers).toEqual([1, 'two', '3DELETE']);
61
+ expect(warnSpy).toHaveBeenCalled();
62
+ });
63
+
64
+ it('builds safe query params only including validated parts', () => {
65
+ const safe = buildSafeQueryParams({
66
+ select: 'id, name, DROP',
67
+ filters: { id: 1, unsafe: 'UNION SELECT *' },
68
+ orderBy: 'created_at DESC',
69
+ limit: 25,
70
+ offset: 5,
71
+ search: " ';DROP",
72
+ });
73
+
74
+ expect(safe.select).toBe('id, name');
75
+ expect(safe.filters).toEqual({ id: 1 });
76
+ expect(safe.orderBy).toBe('created_at DESC');
77
+ expect(safe.limit).toBe(25);
78
+ expect(safe.offset).toBe(5);
79
+ expect(safe.search).toBeUndefined();
80
+ });
81
+
82
+ it('detects SQL injection patterns with risk levels', () => {
83
+ const injection = detectSQLInjection("'; UNION SELECT password FROM users --");
84
+ expect(injection.isSuspicious).toBe(true);
85
+ expect(injection.riskLevel).toBe('critical');
86
+ expect(injection.patterns.length).toBeGreaterThan(0);
87
+
88
+ const benign = detectSQLInjection('12345');
89
+ expect(benign.isSuspicious).toBe(false);
90
+ expect(benign.riskLevel).toBe('low');
91
+ });
92
+ });
package/src/vite-env.d.ts CHANGED
@@ -9,8 +9,8 @@ interface ImportMetaEnv {
9
9
  // Add other environment variables as needed
10
10
  readonly VITE_APP_NAME?: string
11
11
  readonly VITE_SUPABASE_URL?: string
12
- // Accepts both legacy anon keys and modern publishable keys (sb_publishable_...)
13
- readonly VITE_SUPABASE_ANON_KEY?: string
12
+ // Publishable key (sb_publishable_...)
13
+ readonly VITE_SUPABASE_PUBLISHABLE_KEY?: string
14
14
  }
15
15
 
16
16
  interface ImportMeta {