@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/LoadingSpinner/LoadingSpinner.tsx","../src/utils/timezone/timezone.ts","../src/utils/app/appIdResolver.ts"],"sourcesContent":["/**\n * @file LoadingSpinner Component\n * @package @jmruthers/pace-core\n * @module Components/LoadingSpinner\n * @since 0.1.0\n *\n * A simple, accessible loading spinner component for indicating loading states.\n * Provides smooth animations with reduced motion support for accessibility.\n *\n * Features:\n * - Multiple size variants (sm, md, lg)\n * - Smooth CSS animations\n * - Reduced motion support for accessibility\n * - Screen reader friendly with proper ARIA attributes\n * - Customizable styling\n * - Lightweight and performant\n *\n * @example\n * ```tsx\n * // Basic loading spinner\n * <LoadingSpinner />\n * \n * // Different sizes\n * <LoadingSpinner size=\"sm\" />\n * <LoadingSpinner size=\"md\" />\n * <LoadingSpinner size=\"lg\" />\n * \n * // With custom styling\n * <LoadingSpinner \n * size=\"lg\" \n * className=\"text-main-500\" \n * />\n * \n * // In a button\n * <Button disabled>\n * <LoadingSpinner size=\"sm\" className=\"mr-2\" />\n * Loading...\n * </Button>\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Proper ARIA role=\"status\"\n * - Screen reader announcement with \"Loading...\" text\n * - Reduced motion support for users with vestibular disorders\n * - High contrast support\n *\n * @performance\n * - CSS-only animations for optimal performance\n * - No JavaScript dependencies\n * - Minimal DOM structure\n * - Efficient rendering\n *\n * @dependencies\n * - React 19+ - Component framework\n * - Tailwind CSS - Styling and animations\n */\n\nimport React from 'react';\n\n/**\n * Props for the LoadingSpinner component\n */\nexport interface LoadingSpinnerProps {\n /** Size variant of the spinner */\n size?: 'sm' | 'md' | 'lg';\n /** Additional CSS classes for styling */\n className?: string;\n}\n\n/**\n * LoadingSpinner component\n * A simple, accessible loading spinner for indicating loading states\n * \n * @param props - Spinner configuration and styling\n * @returns JSX.Element - The rendered loading spinner\n * \n * @example\n * ```tsx\n * <LoadingSpinner size=\"lg\" className=\"text-main-500\" />\n * ```\n */\nexport const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({ \n size = 'md', \n className = '' \n}) => {\n const sizeClasses: Record<'sm' | 'md' | 'lg', string> = {\n sm: 'size-4',\n md: 'size-6',\n lg: 'size-8'\n };\n\n // Ensure we always have a valid size class, defaulting to 'md' if invalid\n const validSize = size && size in sizeClasses ? size : 'md';\n const sizeClass = sizeClasses[validSize];\n\n return (\n <canvas className={`inline-block animate-spin rounded-full border-2 border-solid border-current border-r-transparent motion-reduce:animate-[spin_1.5s_linear_infinite] ${sizeClass} ${className}`.trim()} role=\"status\">\n <span className=\"sr-only\">Loading...</span>\n </canvas>\n );\n};\n","/**\n * @file Timezone Utilities\n * @package @jmruthers/pace-core\n * @module Utils/Timezone\n * @since 0.1.0\n *\n * Comprehensive timezone conversion and formatting utilities using date-fns-tz and native Intl APIs.\n * Provides functions for timezone-aware date operations, conversions, and formatting.\n *\n * Features:\n * - Format dates in specific timezones\n * - Get timezone abbreviations\n * - Convert between UTC and timezone local times\n * - Round dates to nearest minutes\n * - Calculate timezone differences\n * - Get user's browser timezone\n *\n * @example\n * ```ts\n * import { toZonedTime, fromZonedTime, formatInTimeZone, getUserTimeZone } from '@jmruthers/pace-core/utils/timezone';\n *\n * // Convert UTC to local timezone\n * const utcDate = new Date('2024-01-15T10:00:00Z');\n * const localDate = toZonedTime(utcDate, 'America/New_York');\n *\n * // Convert local time to UTC\n * const localInput = new Date(2024, 0, 15, 10, 0);\n * const utcDate = fromZonedTime(localInput, 'America/New_York');\n *\n * // Format with timezone\n * const formatted = formatInTimeZone(utcDate, 'America/New_York', 'MMM dd, yyyy HH:mm');\n * ```\n */\n\nimport { format, parseISO, addMinutes, differenceInHours, isValid } from 'date-fns';\nimport { formatInTimeZone as fnsFormatInTimeZone, toZonedTime as fnsToZonedTime, fromZonedTime as fnsFromZonedTime } from 'date-fns-tz';\n\n/**\n * Format a date in a specific timezone using date-fns format strings\n *\n * @param date - Date to format (Date object, ISO string, or timestamp)\n * @param timeZone - IANA timezone string (e.g., 'America/New_York')\n * @param formatStr - date-fns format string (e.g., 'MMM dd, yyyy HH:mm')\n * @returns Formatted date string or 'Invalid date' on error\n *\n * @example\n * ```ts\n * formatInTimeZone(new Date('2024-01-15T10:00:00Z'), 'America/New_York', 'MMM dd, yyyy HH:mm');\n * // \"Jan 15, 2024 05:00\"\n * ```\n */\nexport function formatInTimeZone(\n date: Date | string | number,\n timeZone: string,\n formatStr: string\n): string {\n try {\n if (!timeZone || typeof timeZone !== 'string') {\n return 'Invalid date';\n }\n\n let dateObj: Date;\n if (typeof date === 'string') {\n dateObj = parseISO(date);\n } else if (typeof date === 'number') {\n dateObj = new Date(date);\n } else {\n dateObj = date;\n }\n\n if (!isValid(dateObj)) {\n return 'Invalid date';\n }\n\n return fnsFormatInTimeZone(dateObj, timeZone, formatStr);\n } catch {\n return 'Invalid date';\n }\n}\n\n/**\n * Get the timezone abbreviation (EST, PST, etc.) for a date in a specific timezone\n *\n * @param date - Date to get abbreviation for\n * @param timeZone - IANA timezone string\n * @returns Timezone abbreviation or timezone name on error\n *\n * @example\n * ```ts\n * getTimezoneAbbreviation(new Date(), 'America/New_York');\n * // \"EST\" or \"EDT\" depending on date\n * ```\n */\nexport function getTimezoneAbbreviation(date: Date, timeZone: string): string {\n try {\n if (!timeZone || typeof timeZone !== 'string') {\n return timeZone || 'UTC';\n }\n\n if (!isValid(date)) {\n return timeZone;\n }\n\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone,\n timeZoneName: 'short'\n });\n\n const parts = formatter.formatToParts(date);\n const timeZoneName = parts.find(part => part.type === 'timeZoneName');\n\n return timeZoneName?.value || timeZone;\n } catch {\n return timeZone || 'UTC';\n }\n}\n\n/**\n * Format time only in a specific timezone\n *\n * @param date - Date to format\n * @param timeZone - IANA timezone string\n * @returns Formatted time string (HH:mm format) or 'Invalid date' on error\n *\n * @example\n * ```ts\n * formatTimeInTimeZone(new Date('2024-01-15T10:00:00Z'), 'America/New_York');\n * // \"05:00\"\n * ```\n */\nexport function formatTimeInTimeZone(date: Date | string, timeZone: string): string {\n return formatInTimeZone(date, timeZone, 'HH:mm');\n}\n\n/**\n * Get the user's local timezone from the browser\n *\n * @returns IANA timezone string (e.g., 'America/New_York')\n *\n * @example\n * ```ts\n * const userTz = getUserTimeZone();\n * // \"America/New_York\" or user's actual timezone\n * ```\n */\nexport function getUserTimeZone(): string {\n try {\n if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n }\n return 'UTC';\n } catch {\n return 'UTC';\n }\n}\n\n/**\n * Convert a UTC date to a specific timezone's local time representation\n *\n * @param date - UTC date to convert\n * @param timezone - IANA timezone string\n * @returns Date object representing local time in the timezone\n *\n * @example\n * ```ts\n * const utcDate = new Date('2024-01-15T10:00:00Z');\n * const localDate = toZonedTime(utcDate, 'America/New_York');\n * // Returns Date object representing 5:00 AM in New York\n * ```\n */\nexport function toZonedTime(date: Date, timezone: string): Date {\n try {\n if (!timezone || typeof timezone !== 'string') {\n return date;\n }\n\n if (!isValid(date)) {\n return date;\n }\n\n return fnsToZonedTime(date, timezone);\n } catch {\n return date;\n }\n}\n\n/**\n * Convert a local time in a specific timezone to UTC\n *\n * @param localDate - Local date in the timezone\n * @param timezone - IANA timezone string\n * @returns Date object in UTC\n *\n * @example\n * ```ts\n * const localDate = new Date(2024, 0, 15, 10, 0); // Jan 15, 2024 10:00 AM local\n * const utcDate = fromZonedTime(localDate, 'America/New_York');\n * // Returns Date object representing 3:00 PM UTC (if EST) or 2:00 PM UTC (if EDT)\n * ```\n */\nexport function fromZonedTime(localDate: Date, timezone: string): Date {\n try {\n if (!timezone || typeof timezone !== 'string') {\n return localDate;\n }\n\n if (!isValid(localDate)) {\n return localDate;\n }\n\n return fnsFromZonedTime(localDate, timezone);\n } catch {\n return localDate;\n }\n}\n\n/**\n * Round a date to the nearest X minutes\n *\n * @param date - Date to round\n * @param minutesStep - Number of minutes to round to (default: 5)\n * @returns Rounded date\n *\n * @example\n * ```ts\n * const date = new Date('2024-01-15T10:23:00Z');\n * roundToNearestMinutes(date, 5);\n * // Returns Date object for 10:25:00\n * ```\n */\nexport function roundToNearestMinutes(date: Date, minutesStep: number = 5): Date {\n try {\n if (!isValid(date)) {\n return date;\n }\n\n if (minutesStep <= 0 || !Number.isInteger(minutesStep)) {\n return date;\n }\n\n const minutes = date.getMinutes();\n const roundedMinutes = Math.round(minutes / minutesStep) * minutesStep;\n const diff = roundedMinutes - minutes;\n\n return addMinutes(date, diff);\n } catch {\n return date;\n }\n}\n\n/**\n * Calculate the time difference between two timezones in hours\n *\n * @param fromTimeZone - Source timezone (IANA string)\n * @param toTimeZone - Target timezone (IANA string)\n * @returns Difference in hours (positive if toTimeZone is ahead)\n *\n * @example\n * ```ts\n * getTimeZoneDifference('America/New_York', 'America/Los_Angeles');\n * // -3 (Los Angeles is 3 hours behind New York)\n * ```\n */\nexport function getTimeZoneDifference(fromTimeZone: string, toTimeZone: string): number {\n try {\n if (!fromTimeZone || !toTimeZone || typeof fromTimeZone !== 'string' || typeof toTimeZone !== 'string') {\n return 0;\n }\n\n const now = new Date();\n const fromDate = toZonedTime(now, fromTimeZone);\n const toDate = toZonedTime(now, toTimeZone);\n\n const diff = differenceInHours(toDate, fromDate);\n // Handle NaN case (differenceInHours can return NaN for invalid dates)\n return isNaN(diff) ? 0 : diff;\n } catch {\n return 0;\n }\n}\n\n","/**\n * App ID Resolution Utility\n * @package @jmruthers/pace-core\n * @module Utils/AppIdResolver\n * @since 1.0.0\n * \n * This module provides utilities to resolve app names to app IDs for database operations.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../../types/database';\nimport { createLogger } from '../core/logger';\n\nconst log = createLogger('AppIdResolver');\n\n/**\n * Resolves an app name to its corresponding app ID\n * \n * @param supabase - Supabase client instance\n * @param appName - The app name to resolve\n * @returns Promise resolving to the app ID or null if not found\n */\nexport async function getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n): Promise<string | null> {\n try {\n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id')\n .ilike('name', appName)\n .eq('is_active', true)\n .single();\n\n if (error) {\n log.error('Failed to resolve app ID for app name:', appName, error);\n return null;\n }\n\n return (data as { id: string } | null)?.id || null;\n } catch (error) {\n log.error('Error resolving app ID for app name:', appName, error);\n return null;\n }\n}\n\n/**\n * Resolves multiple app names to their corresponding app IDs\n * \n * @param supabase - Supabase client instance\n * @param appNames - Array of app names to resolve\n * @returns Promise resolving to a map of app names to app IDs\n */\nexport async function getAppIds(\n supabase: SupabaseClient<Database>,\n appNames: string[]\n): Promise<Record<string, string | null>> {\n try {\n // For case-insensitive matching with multiple values, we need to use OR conditions\n // since PostgreSQL doesn't support case-insensitive IN with ILIKE\n const orConditions = appNames.map(name => `name.ilike.${name}`).join(',');\n \n const { data, error } = await supabase\n .from('rbac_apps')\n .select('id, name')\n .or(orConditions)\n .eq('is_active', true);\n\n if (error) {\n log.error('Failed to resolve app IDs for app names:', appNames, error);\n return {};\n }\n\n const result: Record<string, string | null> = {};\n \n // Initialize all app names with null\n appNames.forEach(name => {\n result[name] = null;\n });\n\n // Set resolved app IDs - match case-insensitively\n (data as { id: string; name: string }[] | null)?.forEach(app => {\n // Find the original app name that matches (case-insensitive)\n const originalName = appNames.find(name => \n name.toLowerCase() === app.name.toLowerCase()\n );\n if (originalName) {\n result[originalName] = app.id;\n }\n });\n\n return result;\n } catch (error) {\n log.error('Error resolving app IDs for app names:', appNames, error);\n return {};\n }\n}\n\n/**\n * Cached app ID resolver with TTL\n */\nexport class CachedAppIdResolver {\n private cache = new Map<string, { id: string | null; expires: number }>();\n private ttl = 5 * 60 * 1000; // 5 minutes\n\n async getAppId(\n supabase: SupabaseClient<Database>,\n appName: string\n ): Promise<string | null> {\n const now = Date.now();\n const cached = this.cache.get(appName);\n\n if (cached && cached.expires > now) {\n return cached.id;\n }\n\n const id = await getAppId(supabase, appName);\n this.cache.set(appName, { id, expires: now + this.ttl });\n\n return id;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n clearCacheForApp(appName: string): void {\n this.cache.delete(appName);\n }\n}\n\n// Export singleton instance\nexport const cachedAppIdResolver = new CachedAppIdResolver();\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- //# sourceMappingURL=chunk-KQCRWDSA.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/theming/parseEventColours.ts","../src/theming/runtime.ts"],"sourcesContent":["/**\n * @file Event Colours Parser\n * @package @jmruthers/pace-core\n * @module Theming/ParseEventColours\n * @since 2.0.0\n * \n * Shared utility for parsing and normalizing event_colours from database.\n * Handles multiple input formats and ensures consistent palette structure.\n */\n\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('ParseEventColours');\n\n/**\n * Parse and normalize event_colours to PaletteData\n * \n * Supports input formats:\n * - Object with 'main', 'sec', 'acc' keys\n * - JSON string that will be parsed\n * \n * Only includes explicitly defined color values. Does not fill\n * missing shades - only shades that are present in the input will\n * be included in the output.\n * \n * @param input - Event colours from database (JSONB field)\n * @returns Normalized palette data with main, sec, acc palettes, or null if invalid\n * \n * @example\n * ```ts\n * // Standard format\n * const colours = {\n * main: { 500: { L: 0.5, C: 0.2, H: 0 }, raw: { L: 0.5, C: 0.2, H: 0 } },\n * sec: { 500: { L: 0.5, C: 0.2, H: 120 } },\n * acc: { 500: { L: 0.5, C: 0.2, H: 240 } }\n * };\n * const palette = parseAndNormalizeEventColours(colours);\n * // Returns: { main: { 500: {...}, raw: {...} }, sec: { 500: {...} }, acc: { 500: {...} } }\n * ```\n * \n */\nexport function parseAndNormalizeEventColours(input: unknown): { main: any; sec: any; acc: any } | null {\n try {\n if (!input) return null;\n let obj: any = input;\n \n // Handle string input (JSON string from database)\n if (typeof input === 'string') {\n try {\n obj = JSON.parse(input);\n } catch {\n return null;\n }\n } else if (typeof input !== 'object') {\n return null;\n }\n\n // Use standard 'main'/'sec'/'acc' keys\n const main = obj?.main || null;\n const sec = obj?.sec || null;\n const acc = obj?.acc || null;\n \n // If no palette data found, return null\n if (!main && !sec && !acc) return null;\n\n // Helper: only include explicitly defined color values\n // This ensures we don't include undefined shades in the palette\n const fill = (p: any) => {\n if (!p || typeof p !== 'object') return {} as any;\n const out: any = {};\n \n // Only include shades that are explicitly defined in the input\n // Iterate over all keys in the palette object\n for (const key in p) {\n // Only include the key if it has a defined value (not null, undefined, or empty)\n const value = p[key];\n if (value !== null && value !== undefined && value !== '') {\n out[key] = value;\n }\n }\n \n return out;\n };\n\n return { \n main: fill(main), \n sec: fill(sec), \n acc: fill(acc) \n };\n } catch (error) {\n log.warn('Failed to parse/normalize event colours:', error);\n return null;\n }\n}\n\n","/**\n * @file PACE Core Theming Runtime\n * @package @jmruthers/pace-core\n * @module Theming/Runtime\n * @since 2.0.0\n * \n * Runtime helpers for palette replacement from organisation/event payloads.\n * Provides simple applyPalette() and clearPalette() API with SSR support.\n */\n\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('ThemingRuntime');\n\n/**\n * @example\n * ```ts\n * import { applyPalette, clearPalette } from '@jmruthers/pace-core/theming/runtime';\n * \n * // Apply organisation colors\n * applyPalette({\n * main: { // main palette shades\n * 50: { L: 0.95, C: 0.02, H: 0 },\n * 500: { L: 0.5, C: 0.2, H: 0 }\n * },\n * sec: { // secondary palette shades\n * 50: { L: 0.95, C: 0.02, H: 120 },\n * 500: { L: 0.5, C: 0.2, H: 120 }\n * },\n * acc: { // accent palette shades\n * 50: { L: 0.95, C: 0.02, H: 240 },\n * 500: { L: 0.5, C: 0.2, H: 240 }\n * }\n * });\n * \n * // Clear dynamic theming\n * clearPalette();\n * ```\n */\n\nexport interface ColorShade {\n L: number;\n C: number;\n H: number;\n}\n\nexport interface ColorPalette {\n [shade: string]: ColorShade;\n}\n\nexport interface PaletteData {\n main: ColorPalette;\n sec: ColorPalette;\n acc: ColorPalette;\n}\n\n/**\n * Converts OKLCH color data to CSS string\n */\nfunction formatOklchCss(color: ColorShade): string {\n return `oklch(${color.L} ${color.C} ${color.H})`;\n}\n\n/**\n * Applies a complete palette to the document by setting CSS variables on :root.\n * Uses document.documentElement.style.setProperty() for runtime updates.\n * \n * @param palette - Complete palette data with main, sec, and acc palettes\n */\nexport function applyPalette(palette: PaletteData): void {\n if (typeof document === 'undefined' || document === null) {\n log.warn('Document not available (SSR) - palette not applied');\n return;\n }\n\n const root = document.documentElement;\n const main = palette.main || {};\n const sec = palette.sec || {};\n const acc = palette.acc || {};\n\n // Apply main palette\n if (main.raw) {\n root.style.setProperty('--color-main-raw', formatOklchCss(main.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (main[shade]) {\n root.style.setProperty(`--color-main-${shade}`, formatOklchCss(main[shade]));\n }\n }\n\n // Apply sec palette\n if (sec.raw) {\n root.style.setProperty('--color-sec-raw', formatOklchCss(sec.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (sec[shade]) {\n root.style.setProperty(`--color-sec-${shade}`, formatOklchCss(sec[shade]));\n }\n }\n\n // Apply acc palette\n if (acc.raw) {\n root.style.setProperty('--color-acc-raw', formatOklchCss(acc.raw));\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (acc[shade]) {\n root.style.setProperty(`--color-acc-${shade}`, formatOklchCss(acc[shade]));\n }\n }\n\n}\n\n/**\n * Clears dynamic theming by removing CSS variables from :root.\n * This allows the browser to fall back to static CSS values.\n */\nexport function clearPalette(): void {\n if (typeof document === 'undefined' || document === null) {\n return;\n }\n\n const root = document.documentElement;\n const prefixes = ['--color-main-', '--color-sec-', '--color-acc-'];\n \n // Remove all dynamically set color variables\n for (let i = root.style.length - 1; i >= 0; i--) {\n const propertyName = root.style[i];\n if (prefixes.some(prefix => propertyName.startsWith(prefix))) {\n root.style.removeProperty(propertyName);\n }\n }\n}\n\n/**\n * Generates CSS for SSR rendering (for server-side rendering)\n * Creates a :root rule with all color variables\n */\nfunction generateThemeCSS(palette: PaletteData): string {\n // Handle null/undefined palette\n if (!palette) {\n throw new Error('Palette data is required');\n }\n \n const main = palette.main || {};\n const sec = palette.sec || {};\n const acc = palette.acc || {};\n \n let css = ':root {\\n';\n \n // MAIN palette\n css += ' /* MAIN */\\n';\n if (main.raw) {\n css += ` --color-main-raw: ${formatOklchCss(main.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (main[shade]) {\n css += ` --color-main-${shade}: ${formatOklchCss(main[shade])};\\n`;\n }\n }\n \n // SEC palette\n css += ' /* SEC */\\n';\n if (sec.raw) {\n css += ` --color-sec-raw: ${formatOklchCss(sec.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (sec[shade]) {\n css += ` --color-sec-${shade}: ${formatOklchCss(sec[shade])};\\n`;\n }\n }\n \n // ACC palette\n css += ' /* ACC */\\n';\n if (acc.raw) {\n css += ` --color-acc-raw: ${formatOklchCss(acc.raw)};\\n`;\n }\n for (let i = 50; i <= 950; i += 50) {\n const shade = i.toString();\n if (acc[shade]) {\n css += ` --color-acc-${shade}: ${formatOklchCss(acc[shade])};\\n`;\n }\n }\n \n css += '}\\n';\n \n return css;\n}\n\n/**\n * Generates the same CSS block for SSR rendering\n * Use this in your SSR setup to avoid FOUC\n */\nexport function generateSSRThemeCSS(palette: PaletteData): string {\n return generateThemeCSS(palette);\n}\n\n/**\n * Checks if dynamic theming is currently active\n */\nexport function isDynamicThemingActive(): boolean {\n if (typeof document === 'undefined' || document === null) {\n return false;\n }\n \n const root = document.documentElement;\n // Check if any color variables are set on :root\n return root.style.getPropertyValue('--color-main-500') !== '';\n}\n\n/**\n * Gets the current dynamic theme data (if any)\n * Useful for debugging or persistence\n */\nexport function getCurrentThemeData(): PaletteData | null {\n if (typeof document === 'undefined' || document === null) {\n return null;\n }\n\n const root = document.documentElement;\n const main: ColorPalette = {};\n const sec: ColorPalette = {};\n const acc: ColorPalette = {};\n\n // Extract CSS variables from :root\n // This is a simplified implementation\n // In a real scenario, you might want to parse the actual color values\n // For now, we'll return null as the theme data isn't easily extractable\n return null;\n}\n\n// Re-export parseEventColours utility for convenience\nexport { parseAndNormalizeEventColours } from './parseEventColours';"],"mappings":"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","names":["log"]}
@@ -1,84 +0,0 @@
1
- // src/utils/validation/schema.ts
2
- import { z } from "zod";
3
- function pickSchema(schema, keys) {
4
- const shape = Object.entries(schema.shape).filter(([key]) => keys.includes(key)).reduce((acc, [key, value]) => {
5
- acc[key] = value;
6
- return acc;
7
- }, {});
8
- return z.object(shape);
9
- }
10
- function combineSchemas(schemas) {
11
- return schemas.reduce(
12
- (merged, schema) => merged.merge(schema),
13
- z.object({})
14
- );
15
- }
16
-
17
- // src/types/validation.ts
18
- import { z as z2 } from "zod";
19
- var emailSchema = z2.string().email("Please enter a valid email address");
20
- var nameSchema = z2.string().min(1, "Name is required").max(100, "Name must be less than 100 characters");
21
- var phoneSchema = z2.string().regex(/^\+?[\d\s\-\(\)]+$/, "Please enter a valid phone number");
22
- var urlSchema = z2.string().url("Please enter a valid URL");
23
- var dateSchema = z2.string().refine((date) => !isNaN(Date.parse(date)), "Please enter a valid date");
24
- var passwordSchema = z2.string().min(8, "Password must be at least 8 characters").regex(/[A-Z]/, "Password must contain at least one uppercase letter").regex(/[a-z]/, "Password must contain at least one lowercase letter").regex(/[0-9]/, "Password must contain at least one number");
25
- var securePasswordSchema = passwordSchema.regex(/[!@#$%^&*(),.?":{}|<>]/, "Password must contain at least one special character");
26
- var loginSchema = z2.object({
27
- email: emailSchema,
28
- password: z2.string().min(1, "Password is required")
29
- });
30
- var registrationSchema = z2.object({
31
- email: emailSchema,
32
- password: passwordSchema,
33
- confirmPassword: z2.string()
34
- }).refine((data) => data.password === data.confirmPassword, {
35
- message: "Passwords don't match",
36
- path: ["confirmPassword"]
37
- });
38
- var secureLoginSchema = z2.object({
39
- email: emailSchema,
40
- password: securePasswordSchema
41
- });
42
- var passwordResetSchema = z2.object({
43
- email: emailSchema
44
- });
45
- var changePasswordSchema = z2.object({
46
- currentPassword: z2.string().min(1, "Current password is required"),
47
- newPassword: securePasswordSchema,
48
- confirmPassword: z2.string()
49
- }).refine((data) => data.newPassword === data.confirmPassword, {
50
- message: "Passwords don't match",
51
- path: ["confirmPassword"]
52
- });
53
- var userProfileSchema = z2.object({
54
- name: nameSchema,
55
- email: emailSchema,
56
- phone: phoneSchema.optional(),
57
- website: urlSchema.optional(),
58
- bio: z2.string().max(500).optional()
59
- });
60
- var contactFormSchema = z2.object({
61
- name: nameSchema,
62
- email: emailSchema,
63
- message: z2.string().min(1, "Message is required").max(1e3, "Message must be less than 1000 characters")
64
- });
65
-
66
- export {
67
- pickSchema,
68
- combineSchemas,
69
- emailSchema,
70
- nameSchema,
71
- phoneSchema,
72
- urlSchema,
73
- dateSchema,
74
- passwordSchema,
75
- securePasswordSchema,
76
- loginSchema,
77
- registrationSchema,
78
- secureLoginSchema,
79
- passwordResetSchema,
80
- changePasswordSchema,
81
- userProfileSchema,
82
- contactFormSchema
83
- };
84
- //# sourceMappingURL=chunk-LMC26NLJ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/validation/schema.ts","../src/types/validation.ts"],"sourcesContent":["/**\n * @file Schema utility functions\n * @package @jmruthers/pace-core\n * @module Utils/Validation/Schema\n * @since 0.1.0\n * \n * Utility functions for working with Zod schemas.\n */\n\nimport { z } from 'zod';\n\n/**\n * Creates a subset schema from a larger schema\n * \n * @param schema - Original Zod schema\n * @param keys - Array of keys to pick from the schema\n * @returns New schema with only the selected fields\n */\nexport function pickSchema<T extends z.ZodObject<any, any, any>, K extends keyof z.infer<T>>(\n schema: T,\n keys: K[]\n): z.ZodObject<Pick<z.infer<T>, K>> {\n const shape = Object.entries(schema.shape)\n .filter(([key]) => keys.includes(key as K))\n .reduce((acc, [key, value]) => {\n (acc as Record<string, unknown>)[key] = value as unknown;\n return acc;\n }, {} as Record<string, unknown>);\n\n return z.object(shape as Record<string, z.ZodTypeAny>) as z.ZodObject<Pick<z.infer<T>, K>>;\n}\n\n/**\n * Combines multiple Zod schemas into one\n * \n * @param schemas - Array of Zod schemas to combine\n * @returns Combined schema\n */\nexport function combineSchemas<T extends z.ZodObject<any, any, any>[]>(\n schemas: T\n): z.ZodObject<any, any, any> {\n return schemas.reduce(\n (merged, schema) => merged.merge(schema),\n z.object({})\n );\n}\n\n","/**\n * @file Validation Types\n * @package @jmruthers/pace-core\n * @module Types/Validation\n * @since 0.1.0\n * \n * Consolidated validation types and interfaces for the PACE Core library.\n * This file contains all validation-related type definitions.\n */\n\nimport { z } from 'zod';\n\n// ============================================================================\n// Core Validation Interfaces\n// ============================================================================\n\nexport interface ValidationError {\n field: string;\n message: string;\n code: string;\n}\n\nexport interface ValidationResult<T = unknown> {\n success: boolean;\n data?: T;\n errors?: ValidationError[];\n}\n\n// ============================================================================\n// Form Value Types\n// ============================================================================\n\n// Basic form schemas\nexport const emailSchema = z.string().email('Please enter a valid email address');\nexport const nameSchema = z.string().min(1, 'Name is required').max(100, 'Name must be less than 100 characters');\nexport const phoneSchema = z.string().regex(/^\\+?[\\d\\s\\-\\(\\)]+$/, 'Please enter a valid phone number');\nexport const urlSchema = z.string().url('Please enter a valid URL');\nexport const dateSchema = z.string().refine((date) => !isNaN(Date.parse(date)), 'Please enter a valid date');\n\n// Password schemas\nexport const passwordSchema = z.string()\n .min(8, 'Password must be at least 8 characters')\n .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')\n .regex(/[a-z]/, 'Password must contain at least one lowercase letter')\n .regex(/[0-9]/, 'Password must contain at least one number');\n\nexport const securePasswordSchema = passwordSchema\n .regex(/[!@#$%^&*(),.?\":{}|<>]/, 'Password must contain at least one special character');\n\n// Auth schemas\nexport const loginSchema = z.object({\n email: emailSchema,\n password: z.string().min(1, 'Password is required'),\n});\n\nexport const registrationSchema = z.object({\n email: emailSchema,\n password: passwordSchema,\n confirmPassword: z.string(),\n}).refine((data) => data.password === data.confirmPassword, {\n message: \"Passwords don't match\",\n path: [\"confirmPassword\"],\n});\n\nexport const secureLoginSchema = z.object({\n email: emailSchema,\n password: securePasswordSchema,\n});\n\nexport const passwordResetSchema = z.object({\n email: emailSchema,\n});\n\nexport const changePasswordSchema = z.object({\n currentPassword: z.string().min(1, 'Current password is required'),\n newPassword: securePasswordSchema,\n confirmPassword: z.string(),\n}).refine((data) => data.newPassword === data.confirmPassword, {\n message: \"Passwords don't match\",\n path: ['confirmPassword'],\n});\n\n// User schemas\nexport const userProfileSchema = z.object({\n name: nameSchema,\n email: emailSchema,\n phone: phoneSchema.optional(),\n website: urlSchema.optional(),\n bio: z.string().max(500).optional(),\n});\n\n// Contact form schema\nexport const contactFormSchema = z.object({\n name: nameSchema,\n email: emailSchema,\n message: z.string().min(1, 'Message is required').max(1000, 'Message must be less than 1000 characters'),\n});\n\n// ============================================================================\n// Inferred Types\n// ============================================================================\n\nexport type LoginFormValues = z.infer<typeof loginSchema>;\nexport type RegistrationFormValues = z.infer<typeof registrationSchema>;\nexport type ChangePasswordFormValues = z.infer<typeof changePasswordSchema>;\nexport type UserProfileFormValues = z.infer<typeof userProfileSchema>;\n\n// Secure form types (with CSRF protection)\nexport type SecureLoginFormValues = {\n email: string;\n password: string;\n csrfToken?: string;\n};\n\nexport type SecureRegistrationFormValues = {\n email: string;\n password: string;\n confirmPassword: string;\n csrfToken?: string;\n};\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\nexport type FormData = LoginFormData | RegistrationFormData | ProfileFormData | ContactFormData;\n\nexport type LoginFormData = z.infer<typeof loginSchema>;\nexport type RegistrationFormData = z.infer<typeof registrationSchema>;\nexport type ProfileFormData = z.infer<typeof userProfileSchema>;\nexport type ContactFormData = z.infer<typeof contactFormSchema>;\n\n// ============================================================================\n// Schema Utility Functions\n// ============================================================================\n// Re-exported from utils/validation/schema.ts\nexport { pickSchema, combineSchemas } from '../utils/validation/schema';\n"],"mappings":";AASA,SAAS,SAAS;AASX,SAAS,WACd,QACA,MACkC;AAClC,QAAM,QAAQ,OAAO,QAAQ,OAAO,KAAK,EACtC,OAAO,CAAC,CAAC,GAAG,MAAM,KAAK,SAAS,GAAQ,CAAC,EACzC,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM;AAC7B,IAAC,IAAgC,GAAG,IAAI;AACxC,WAAO;AAAA,EACT,GAAG,CAAC,CAA4B;AAElC,SAAO,EAAE,OAAO,KAAqC;AACvD;AAQO,SAAS,eACd,SAC4B;AAC5B,SAAO,QAAQ;AAAA,IACb,CAAC,QAAQ,WAAW,OAAO,MAAM,MAAM;AAAA,IACvC,EAAE,OAAO,CAAC,CAAC;AAAA,EACb;AACF;;;ACnCA,SAAS,KAAAA,UAAS;AAuBX,IAAM,cAAcA,GAAE,OAAO,EAAE,MAAM,oCAAoC;AACzE,IAAM,aAAaA,GAAE,OAAO,EAAE,IAAI,GAAG,kBAAkB,EAAE,IAAI,KAAK,uCAAuC;AACzG,IAAM,cAAcA,GAAE,OAAO,EAAE,MAAM,sBAAsB,mCAAmC;AAC9F,IAAM,YAAYA,GAAE,OAAO,EAAE,IAAI,0BAA0B;AAC3D,IAAM,aAAaA,GAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,GAAG,2BAA2B;AAGpG,IAAM,iBAAiBA,GAAE,OAAO,EACpC,IAAI,GAAG,wCAAwC,EAC/C,MAAM,SAAS,qDAAqD,EACpE,MAAM,SAAS,qDAAqD,EACpE,MAAM,SAAS,2CAA2C;AAEtD,IAAM,uBAAuB,eACjC,MAAM,0BAA0B,sDAAsD;AAGlF,IAAM,cAAcA,GAAE,OAAO;AAAA,EAClC,OAAO;AAAA,EACP,UAAUA,GAAE,OAAO,EAAE,IAAI,GAAG,sBAAsB;AACpD,CAAC;AAEM,IAAM,qBAAqBA,GAAE,OAAO;AAAA,EACzC,OAAO;AAAA,EACP,UAAU;AAAA,EACV,iBAAiBA,GAAE,OAAO;AAC5B,CAAC,EAAE,OAAO,CAAC,SAAS,KAAK,aAAa,KAAK,iBAAiB;AAAA,EAC1D,SAAS;AAAA,EACT,MAAM,CAAC,iBAAiB;AAC1B,CAAC;AAEM,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,OAAO;AAAA,EACP,UAAU;AACZ,CAAC;AAEM,IAAM,sBAAsBA,GAAE,OAAO;AAAA,EAC1C,OAAO;AACT,CAAC;AAEM,IAAM,uBAAuBA,GAAE,OAAO;AAAA,EAC3C,iBAAiBA,GAAE,OAAO,EAAE,IAAI,GAAG,8BAA8B;AAAA,EACjE,aAAa;AAAA,EACb,iBAAiBA,GAAE,OAAO;AAC5B,CAAC,EAAE,OAAO,CAAC,SAAS,KAAK,gBAAgB,KAAK,iBAAiB;AAAA,EAC7D,SAAS;AAAA,EACT,MAAM,CAAC,iBAAiB;AAC1B,CAAC;AAGM,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO,YAAY,SAAS;AAAA,EAC5B,SAAS,UAAU,SAAS;AAAA,EAC5B,KAAKA,GAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AACpC,CAAC;AAGM,IAAM,oBAAoBA,GAAE,OAAO;AAAA,EACxC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAASA,GAAE,OAAO,EAAE,IAAI,GAAG,qBAAqB,EAAE,IAAI,KAAM,2CAA2C;AACzG,CAAC;","names":["z"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/core/cn.ts","../src/utils/validation/htmlSanitization.ts"],"sourcesContent":["\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}","/**\n * @file HTML Sanitization Utilities\n * @package @jmruthers/pace-core\n * @module Utils/Validation/HTMLSanitization\n * @since 0.4.36\n * \n * Utilities for safely rendering HTML content.\n * Provides sanitization and validation for basic HTML elements.\n */\n\n/**\n * Allowed HTML tags for safe rendering\n */\nconst ALLOWED_TAGS = [\n 'p', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'strong', 'em', 'b', 'i', 'u', 's', 'mark', 'small', 'sub', 'sup',\n 'ul', 'ol', 'li', 'dl', 'dt', 'dd',\n 'blockquote', 'pre', 'code', 'kbd', 'samp',\n 'a', 'br', 'hr',\n 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td',\n 'img', 'figure', 'figcaption',\n 'section', 'article', 'aside', 'header', 'footer', 'main', 'nav',\n 'details', 'summary'\n] as const;\n\n/**\n * Allowed HTML attributes for safe rendering\n */\nconst ALLOWED_ATTRIBUTES = [\n 'id', 'class', 'style', 'title', 'lang', 'dir',\n 'href', 'target', 'rel', 'download',\n 'src', 'alt', 'width', 'height', 'loading',\n 'colspan', 'rowspan', 'scope', 'headers',\n 'open', 'datetime', 'cite'\n] as const;\n\n/**\n * Basic HTML sanitization function using regex-based approach\n * Removes potentially dangerous elements and attributes while preserving basic formatting\n * This approach is more reliable in SSR environments and doesn't require DOM manipulation\n * \n * @param html - The HTML string to sanitize\n * @returns Sanitized HTML string safe for rendering\n * \n * @example\n * ```tsx\n * const safeHtml = sanitizeHtml('<p>Hello <strong>world</strong>!</p>');\n * // Returns: '<p>Hello <strong>world</strong>!</p>'\n * \n * const dangerousHtml = sanitizeHtml('<script>alert(\"xss\")</script><p>Safe content</p>');\n * // Returns: '<p>Safe content</p>'\n * ```\n */\nexport function sanitizeHtml(html: string): string {\n if (!html || typeof html !== 'string') {\n return '';\n }\n\n // Basic safety: just remove script tags and dangerous attributes\n let sanitized = html\n // Remove script tags (including self-closing and malformed)\n .replace(/<script\\b[^>]*>.*?<\\/script>/gi, '')\n .replace(/<script\\b[^>]*\\/>/gi, '')\n // Remove iframe tags (including self-closing and malformed)\n .replace(/<iframe\\b[^>]*>.*?<\\/iframe>/gi, '')\n .replace(/<iframe\\b[^>]*\\/>/gi, '')\n // Remove object tags (including self-closing and malformed)\n .replace(/<object\\b[^>]*>.*?<\\/object>/gi, '')\n .replace(/<object\\b[^>]*\\/>/gi, '')\n // Remove embed tags (including self-closing)\n .replace(/<embed\\b[^>]*\\/?>/gi, '')\n // Remove form tags (including self-closing and malformed)\n .replace(/<form\\b[^>]*>.*?<\\/form>/gi, '')\n .replace(/<form\\b[^>]*\\/>/gi, '')\n // Remove input tags (including self-closing)\n .replace(/<input\\b[^>]*\\/?>/gi, '')\n // Remove button tags (including self-closing and malformed)\n .replace(/<button\\b[^>]*>.*?<\\/button>/gi, '')\n .replace(/<button\\b[^>]*\\/>/gi, '')\n // Remove event handlers from any remaining tags - correct pattern\n .replace(/\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi, '')\n // Remove javascript: protocols - correct pattern\n .replace(/javascript:[^\"'\\s>]*/gi, '')\n // Remove data: protocols - correct pattern\n .replace(/data:[^\"'\\s>]*/gi, '');\n\n return sanitized;\n}\n\n/**\n * Validates if HTML content is safe for rendering\n * \n * @param html - The HTML string to validate\n * @returns Object with validation result and any warnings\n * \n * @example\n * ```tsx\n * const validation = validateHtml('<p>Safe content</p>');\n * console.log(validation.isValid); // true\n * console.log(validation.warnings); // []\n * ```\n */\nexport function validateHtml(html: string): { isValid: boolean; warnings: string[] } {\n const warnings: string[] = [];\n \n if (!html || typeof html !== 'string') {\n return { isValid: false, warnings: ['HTML content must be a non-empty string'] };\n }\n\n // Check for potentially dangerous patterns\n const dangerousPatterns = [\n { pattern: /<script\\b[^>]*>.*?<\\/script>/gi, message: 'Script tags are not allowed' },\n { pattern: /<script\\b[^>]*\\/>/gi, message: 'Script tags are not allowed' },\n { pattern: /<iframe\\b[^>]*>.*?<\\/iframe>/gi, message: 'Iframe tags are not allowed' },\n { pattern: /<iframe\\b[^>]*\\/>/gi, message: 'Iframe tags are not allowed' },\n { pattern: /<object\\b[^>]*>.*?<\\/object>/gi, message: 'Object tags are not allowed' },\n { pattern: /<object\\b[^>]*\\/>/gi, message: 'Object tags are not allowed' },\n { pattern: /<embed\\b[^>]*\\/?>/gi, message: 'Embed tags are not allowed' },\n { pattern: /<form\\b[^>]*>.*?<\\/form>/gi, message: 'Form tags are not allowed' },\n { pattern: /<form\\b[^>]*\\/>/gi, message: 'Form tags are not allowed' },\n { pattern: /<input\\b[^>]*\\/?>/gi, message: 'Input tags are not allowed' },\n { pattern: /<button\\b[^>]*>.*?<\\/button>/gi, message: 'Button tags are not allowed' },\n { pattern: /<button\\b[^>]*\\/>/gi, message: 'Button tags are not allowed' },\n { pattern: /on\\w+\\s*=/gi, message: 'Event handlers are not allowed' },\n { pattern: /javascript:/gi, message: 'JavaScript protocols are not allowed' },\n { pattern: /data:/gi, message: 'Data protocols are not allowed' }\n ];\n\n dangerousPatterns.forEach(({ pattern, message }) => {\n if (pattern.test(html)) {\n warnings.push(message);\n }\n });\n\n return {\n isValid: warnings.length === 0,\n warnings\n };\n}\n\n/**\n * Safely renders HTML content with sanitization\n * \n * @param html - The HTML string to render\n * @param options - Rendering options\n * @returns Object with sanitized HTML and validation info\n * \n * @example\n * ```tsx\n * const result = renderSafeHtml('<p>Hello <strong>world</strong>!</p>');\n * console.log(result.html); // Sanitized HTML\n * console.log(result.isValid); // true\n * ```\n */\nexport function renderSafeHtml(\n html: string, \n options: { \n strict?: boolean; \n logWarnings?: boolean;\n } = {}\n): { \n html: string; \n isValid: boolean; \n warnings: string[] \n} {\n const { strict = true, logWarnings = false } = options;\n \n const validation = validateHtml(html);\n const sanitizedHtml = sanitizeHtml(html);\n \n if (logWarnings && validation.warnings.length > 0) {\n // Use logger if needed, but this is controlled by logWarnings option\n // For now, keep console.warn as it's only called when explicitly requested\n // via logWarnings option, which is typically for debugging\n console.warn('HTML content warnings:', validation.warnings);\n }\n \n return {\n html: sanitizedHtml,\n isValid: validation.isValid,\n warnings: validation.warnings\n };\n}\n\n"],"mappings":";AACA,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC+CO,SAAS,aAAa,MAAsB;AACjD,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AAGA,MAAI,YAAY,KAEb,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,qBAAqB,EAAE,EAE/B,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,mCAAmC,EAAE,EAE7C,QAAQ,0BAA0B,EAAE,EAEpC,QAAQ,oBAAoB,EAAE;AAEjC,SAAO;AACT;AAeO,SAAS,aAAa,MAAwD;AACnF,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO,EAAE,SAAS,OAAO,UAAU,CAAC,yCAAyC,EAAE;AAAA,EACjF;AAGA,QAAM,oBAAoB;AAAA,IACxB,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,uBAAuB,SAAS,6BAA6B;AAAA,IACxE,EAAE,SAAS,8BAA8B,SAAS,4BAA4B;AAAA,IAC9E,EAAE,SAAS,qBAAqB,SAAS,4BAA4B;AAAA,IACrE,EAAE,SAAS,uBAAuB,SAAS,6BAA6B;AAAA,IACxE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,eAAe,SAAS,iCAAiC;AAAA,IACpE,EAAE,SAAS,iBAAiB,SAAS,uCAAuC;AAAA,IAC5E,EAAE,SAAS,WAAW,SAAS,iCAAiC;AAAA,EAClE;AAEA,oBAAkB,QAAQ,CAAC,EAAE,SAAS,QAAQ,MAAM;AAClD,QAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,eAAS,KAAK,OAAO;AAAA,IACvB;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,SAAS,SAAS,WAAW;AAAA,IAC7B;AAAA,EACF;AACF;AAgBO,SAAS,eACd,MACA,UAGI,CAAC,GAKL;AACA,QAAM,EAAE,SAAS,MAAM,cAAc,MAAM,IAAI;AAE/C,QAAM,aAAa,aAAa,IAAI;AACpC,QAAM,gBAAgB,aAAa,IAAI;AAEvC,MAAI,eAAe,WAAW,SAAS,SAAS,GAAG;AAIjD,YAAQ,KAAK,0BAA0B,WAAW,QAAQ;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,WAAW;AAAA,IACpB,UAAU,WAAW;AAAA,EACvB;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/app/appNameResolver.ts"],"sourcesContent":["/**\n * Utility to resolve the current app name from various sources\n * Priority: package.json > environment variables > fallback\n */\n\nimport { createLogger } from '../core/logger';\n\nconst log = createLogger('AppNameResolver');\n\ninterface PackageJson {\n name: string;\n [key: string]: unknown;\n}\n\n/**\n * Get the app name from package.json at build time\n * This works by reading package.json during the build process\n */\nexport function getAppNameFromPackageJson(): string | null {\n // Check if we're in a Node.js environment (build time)\n if (typeof window === 'undefined' && typeof require !== 'undefined') {\n try {\n // Try to read package.json from the current working directory\n // This works in most Node.js environments\n const fs = require('fs');\n const path = require('path');\n \n // Look for package.json in common locations\n const possiblePaths = [\n // Only use process.cwd() if we're in a Node.js environment\n ...(typeof process !== 'undefined' && process.cwd ? [path.join(process.cwd(), 'package.json')] : []),\n path.join(__dirname, '../../package.json'),\n path.join(__dirname, '../../../package.json'),\n ];\n \n for (const packagePath of possiblePaths) {\n try {\n if (fs.existsSync(packagePath)) {\n const packageJsonContent = fs.readFileSync(packagePath, 'utf8');\n const packageJson: PackageJson = JSON.parse(packageJsonContent);\n \n if (packageJson.name) {\n // Extract the app name from the package name\n // Handle scoped packages like @org/app-name\n const name = packageJson.name.split('/').pop() || packageJson.name;\n return name;\n }\n }\n } catch (error) {\n // Continue to next path\n continue;\n }\n }\n } catch (error) {\n // package.json not found or not readable\n log.warn('Could not read app name from package.json:', error);\n }\n }\n \n // In browser environments, we can't read package.json\n // This will fall back to environment variables\n return null;\n}\n\n/**\n * Get the app name from build-time injected variables\n * This is the preferred method for browser environments\n */\nexport function getAppNameFromBuildTime(): string | null {\n // Check for build-time injected app name\n // This would be set by the build process reading package.json\n if (typeof window !== 'undefined') {\n // Try to access build-time injected variables\n try {\n // @ts-ignore - These are injected at build time\n const buildTimeEnv = (globalThis as any).__RBAC_APP_NAME__;\n if (buildTimeEnv && buildTimeEnv.trim()) {\n return buildTimeEnv.trim();\n }\n } catch (error) {\n // Build-time injection not available\n }\n }\n \n return null;\n}\n\n/**\n * Get the app name from a global variable set by the consuming app\n * This is the simplest approach for browser environments\n */\nexport function getAppNameFromGlobal(): string | null {\n if (typeof window !== 'undefined') {\n // Check for global app name set by consuming app\n try {\n // @ts-ignore - This is set by the consuming app\n const globalAppName = (globalThis as any).RBAC_APP_NAME;\n if (globalAppName && globalAppName.trim()) {\n return globalAppName.trim();\n }\n } catch (error) {\n // Global variable not set\n }\n }\n \n return null;\n}\n\n/**\n * Get the app name from environment variables\n * Fallback method for when package.json is not available\n */\nexport function getAppNameFromEnvironment(): string | null {\n // Try different environment variable patterns used by various frameworks\n const envVars = [\n 'VITE_APP_NAME',\n 'REACT_APP_NAME', \n 'NEXT_PUBLIC_APP_NAME',\n 'APP_NAME',\n 'NODE_APP_NAME'\n ];\n \n for (const envVar of envVars) {\n const value = import.meta.env[envVar];\n if (value && value.trim()) {\n return value.trim();\n }\n }\n \n return null;\n}\n\n/**\n * Get the current app name from the most reliable source\n * Priority: global variable > build-time injection > package.json > environment variables > null\n */\nexport function getCurrentAppName(): string | null {\n // First try global variable (set by consuming app)\n const globalName = getAppNameFromGlobal();\n if (globalName) {\n return globalName;\n }\n \n // Then try build-time injection (most reliable for browser)\n const buildTimeName = getAppNameFromBuildTime();\n if (buildTimeName) {\n return buildTimeName;\n }\n \n // Then try package.json (works in Node.js environments)\n const packageJsonName = getAppNameFromPackageJson();\n if (packageJsonName) {\n return packageJsonName;\n }\n \n // Fallback to environment variables\n const envName = getAppNameFromEnvironment();\n if (envName) {\n return envName;\n }\n \n return null;\n}\n\n/**\n * Set the app name globally for RBAC resolution\n * Call this in your app's main entry point (e.g., main.tsx, index.tsx)\n * \n * @param appName - The app name from your package.json\n * \n * @example\n * ```tsx\n * // In your main.tsx or index.tsx\n * import { setRBACAppName } from '@jmruthers/pace-core/utils';\n * \n * // Set the app name from package.json\n * setRBACAppName('CAKE');\n * \n * // Rest of your app setup...\n * ```\n */\nexport function setRBACAppName(appName: string): void {\n if (typeof window !== 'undefined') {\n // @ts-ignore - Setting global variable\n (globalThis as any).RBAC_APP_NAME = appName.trim();\n }\n}\n\n/**\n * Get the app name with fallback to a default\n * Useful when you need a guaranteed app name\n */\nexport function getCurrentAppNameWithFallback(fallback: string = 'default-app'): string {\n return getCurrentAppName() || fallback;\n}\n"],"mappings":";;;;;;;;AAOA,IAAM,MAAM,aAAa,iBAAiB;AAWnC,SAAS,4BAA2C;AAEzD,MAAI,OAAO,WAAW,eAAe,OAAO,cAAY,aAAa;AACnE,QAAI;AAGF,YAAM,KAAK,UAAQ,IAAI;AACvB,YAAM,OAAO,UAAQ,MAAM;AAG3B,YAAM,gBAAgB;AAAA;AAAA,QAEpB,GAAI,OAAO,YAAY,eAAe,QAAQ,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC;AAAA,QAClG,KAAK,KAAK,WAAW,oBAAoB;AAAA,QACzC,KAAK,KAAK,WAAW,uBAAuB;AAAA,MAC9C;AAEA,iBAAW,eAAe,eAAe;AACvC,YAAI;AACF,cAAI,GAAG,WAAW,WAAW,GAAG;AAC9B,kBAAM,qBAAqB,GAAG,aAAa,aAAa,MAAM;AAC9D,kBAAM,cAA2B,KAAK,MAAM,kBAAkB;AAE9D,gBAAI,YAAY,MAAM;AAGpB,oBAAM,OAAO,YAAY,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,YAAY;AAC9D,qBAAO;AAAA,YACT;AAAA,UACF;AAAA,QACF,SAAS,OAAO;AAEd;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,KAAK,8CAA8C,KAAK;AAAA,IAC9D;AAAA,EACF;AAIA,SAAO;AACT;AAMO,SAAS,0BAAyC;AAGvD,MAAI,OAAO,WAAW,aAAa;AAEjC,QAAI;AAEF,YAAM,eAAgB,WAAmB;AACzC,UAAI,gBAAgB,aAAa,KAAK,GAAG;AACvC,eAAO,aAAa,KAAK;AAAA,MAC3B;AAAA,IACF,SAAS,OAAO;AAAA,IAEhB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,uBAAsC;AACpD,MAAI,OAAO,WAAW,aAAa;AAEjC,QAAI;AAEF,YAAM,gBAAiB,WAAmB;AAC1C,UAAI,iBAAiB,cAAc,KAAK,GAAG;AACzC,eAAO,cAAc,KAAK;AAAA,MAC5B;AAAA,IACF,SAAS,OAAO;AAAA,IAEhB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,4BAA2C;AAEzD,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,aAAW,UAAU,SAAS;AAC5B,UAAM,QAAQ,YAAY,IAAI,MAAM;AACpC,QAAI,SAAS,MAAM,KAAK,GAAG;AACzB,aAAO,MAAM,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,oBAAmC;AAEjD,QAAM,aAAa,qBAAqB;AACxC,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,wBAAwB;AAC9C,MAAI,eAAe;AACjB,WAAO;AAAA,EACT;AAGA,QAAM,kBAAkB,0BAA0B;AAClD,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAGA,QAAM,UAAU,0BAA0B;AAC1C,MAAI,SAAS;AACX,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAmBO,SAAS,eAAe,SAAuB;AACpD,MAAI,OAAO,WAAW,aAAa;AAEjC,IAAC,WAAmB,gBAAgB,QAAQ,KAAK;AAAA,EACnD;AACF;AAMO,SAAS,8BAA8B,WAAmB,eAAuB;AACtF,SAAO,kBAAkB,KAAK;AAChC;","names":[]}