@jmruthers/pace-core 0.5.189 → 0.5.190
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.
- package/core-usage-manifest.json +0 -4
- package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
- package/dist/{DataTable-GUFUNZ3N.js → DataTable-ON3IXISJ.js} +8 -8
- package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-C4uxosp6.d.ts} +83 -24
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-X5NXANVI.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-I6UCQ5S6.js} +4 -2
- package/dist/{chunk-DDM4CCYT.js → chunk-4QYC5L4K.js} +60 -35
- package/dist/chunk-4QYC5L4K.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-73HSNNOQ.js} +141 -326
- package/dist/chunk-73HSNNOQ.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-DZWK57KZ.js} +2 -75
- package/dist/chunk-DZWK57KZ.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-HQVPB5MZ.js} +238 -301
- package/dist/chunk-HQVPB5MZ.js.map +1 -0
- package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
- package/dist/chunk-HW3OVDUF.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
- package/dist/chunk-I7PSE6JW.js.map +1 -0
- package/dist/{chunk-VGZZXKBR.js → chunk-J2XXC7R5.js} +280 -52
- package/dist/chunk-J2XXC7R5.js.map +1 -0
- package/dist/{chunk-UCQSRW7Z.js → chunk-NIU6J6OX.js} +425 -378
- package/dist/chunk-NIU6J6OX.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-RUYZKXOD.js} +401 -46
- package/dist/chunk-RUYZKXOD.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-SDMHPX3X.js} +176 -160
- package/dist/{chunk-2UUZZJFT.js.map → chunk-SDMHPX3X.js.map} +1 -1
- package/dist/{chunk-MX64ZF6I.js → chunk-STYK4OH2.js} +11 -11
- package/dist/chunk-STYK4OH2.js.map +1 -0
- package/dist/{chunk-YGPFYGA6.js → chunk-VVBAW5A5.js} +822 -498
- package/dist/chunk-VVBAW5A5.js.map +1 -0
- package/dist/chunk-Y4BUBBHD.js +614 -0
- package/dist/chunk-Y4BUBBHD.js.map +1 -0
- package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
- package/dist/chunk-ZSAAAMVR.js.map +1 -0
- package/dist/components.d.ts +3 -4
- package/dist/components.js +19 -19
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
- package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
- package/dist/hooks.d.ts +10 -5
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.js +79 -69
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +76 -12
- package/dist/rbac/index.js +12 -9
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-DxIDS4bC.d.ts} +16 -9
- package/dist/utils.js +16 -16
- package/docs/README.md +2 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +2 -2
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +2 -2
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +4 -4
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +21 -16
- package/docs/api/classes/StorageUtils.md +7 -4
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +20 -6
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +62 -16
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +26 -12
- package/docs/api/interfaces/FileUploadProps.md +30 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +3 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +4 -4
- package/docs/api/interfaces/StorageFileInfo.md +7 -7
- package/docs/api/interfaces/StorageFileMetadata.md +25 -14
- package/docs/api/interfaces/StorageListOptions.md +22 -9
- package/docs/api/interfaces/StorageListResult.md +4 -4
- package/docs/api/interfaces/StorageUploadOptions.md +21 -8
- package/docs/api/interfaces/StorageUploadResult.md +6 -6
- package/docs/api/interfaces/StorageUrlOptions.md +19 -6
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +151 -92
- package/docs/api-reference/components.md +15 -7
- package/docs/api-reference/providers.md +2 -2
- package/docs/api-reference/rpc-functions.md +1 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/deployment.md +8 -8
- package/docs/getting-started/examples/README.md +2 -2
- package/docs/getting-started/installation-guide.md +4 -4
- package/docs/getting-started/quick-start.md +3 -3
- package/docs/migration/MIGRATION_GUIDE.md +3 -3
- package/docs/rbac/compliance/compliance-guide.md +2 -2
- package/docs/rbac/event-based-apps.md +2 -2
- package/docs/rbac/getting-started.md +2 -2
- package/docs/rbac/quick-start.md +2 -2
- package/docs/security/README.md +4 -4
- package/docs/standards/07-rbac-and-rls-standard.md +430 -7
- package/docs/troubleshooting/README.md +2 -2
- package/docs/troubleshooting/migration.md +3 -3
- package/package.json +1 -3
- package/scripts/check-pace-core-compliance.cjs +1 -1
- package/scripts/check-pace-core-compliance.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +301 -0
- package/src/__tests__/public-recipe-view.test.ts +9 -9
- package/src/__tests__/rls-policies.test.ts +197 -61
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +1 -0
- package/src/components/Alert/Alert.test.tsx +50 -10
- package/src/components/Alert/Alert.tsx +5 -3
- package/src/components/Avatar/Avatar.test.tsx +95 -43
- package/src/components/Avatar/Avatar.tsx +16 -16
- package/src/components/Button/Button.test.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -3
- package/src/components/Calendar/Calendar.test.tsx +53 -37
- package/src/components/Calendar/Calendar.tsx +409 -82
- package/src/components/Card/Card.test.tsx +7 -4
- package/src/components/Card/Card.tsx +3 -6
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +5 -5
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
- package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
- package/src/components/DataTable/components/DataTableBody.tsx +12 -12
- package/src/components/DataTable/components/DataTableCore.tsx +3 -3
- package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
- package/src/components/DataTable/components/EditableRow.tsx +2 -2
- package/src/components/DataTable/components/EmptyState.tsx +3 -3
- package/src/components/DataTable/components/GroupHeader.tsx +2 -2
- package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +4 -4
- package/src/components/DataTable/components/LoadingState.tsx +1 -1
- package/src/components/DataTable/components/PaginationControls.tsx +11 -11
- package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
- package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
- package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/EventSelector/EventSelector.tsx +7 -7
- package/src/components/FileDisplay/FileDisplay.tsx +291 -179
- package/src/components/FileUpload/FileUpload.tsx +7 -4
- package/src/components/Header/Header.test.tsx +28 -0
- package/src/components/Header/Header.tsx +22 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +8 -8
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
- package/src/components/PaceAppLayout/test-setup.tsx +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
- package/src/components/Progress/Progress.test.tsx +18 -19
- package/src/components/Progress/Progress.tsx +31 -32
- package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
- package/src/components/Select/Select.tsx +5 -5
- package/src/components/Switch/Switch.test.tsx +2 -1
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.test.tsx +8 -2
- package/src/components/UserMenu/UserMenu.tsx +3 -3
- package/src/eslint-rules/pace-core-compliance.cjs +0 -2
- package/src/eslint-rules/pace-core-compliance.js +0 -2
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
- package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
- package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
- package/src/hooks/__tests__/{usePublicEvent.unit.test.ts → usePublicEvent.test.ts} +28 -1
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +297 -34
- package/src/hooks/useFileReference.ts +56 -11
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useInactivityTracker.ts +16 -7
- package/src/hooks/usePermissionCache.test.ts +85 -8
- package/src/hooks/useQueryCache.ts +21 -0
- package/src/hooks/useSecureDataAccess.test.ts +80 -35
- package/src/hooks/useSecureDataAccess.ts +80 -37
- package/src/providers/services/EventServiceProvider.tsx +37 -17
- package/src/providers/services/InactivityServiceProvider.tsx +4 -4
- package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
- package/src/rbac/api.ts +240 -36
- package/src/rbac/cache-invalidation.ts +21 -7
- package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
- package/src/rbac/components/NavigationGuard.tsx +23 -63
- package/src/rbac/components/NavigationProvider.test.tsx +52 -23
- package/src/rbac/components/NavigationProvider.tsx +13 -11
- package/src/rbac/components/PagePermissionGuard.tsx +77 -203
- package/src/rbac/components/PagePermissionProvider.tsx +13 -11
- package/src/rbac/components/PermissionEnforcer.tsx +24 -62
- package/src/rbac/components/RoleBasedRouter.tsx +14 -12
- package/src/rbac/components/SecureDataProvider.tsx +13 -11
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
- package/src/rbac/engine.ts +4 -2
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/useCan.test.ts +101 -53
- package/src/rbac/hooks/usePermissions.ts +108 -41
- package/src/rbac/hooks/useRBAC.test.ts +11 -3
- package/src/rbac/hooks/useRBAC.ts +83 -40
- package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
- package/src/rbac/hooks/useResolvedScope.ts +128 -70
- package/src/rbac/hooks/useSecureSupabase.ts +36 -19
- package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
- package/src/rbac/request-deduplication.ts +1 -1
- package/src/rbac/secureClient.ts +72 -12
- package/src/rbac/security.ts +29 -23
- package/src/rbac/types.ts +10 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
- package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +6 -1
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +48 -2
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +37 -2
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/types/file-reference.ts +13 -10
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +61 -33
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- package/src/utils/storage/helpers.test.ts +1 -1
- package/src/utils/storage/helpers.ts +38 -19
- package/src/utils/storage/types.ts +15 -8
- package/src/utils/validation/__tests__/csrf.test.ts +105 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
- package/src/vite-env.d.ts +2 -2
- package/dist/chunk-3GOZZZYH.js.map +0 -1
- package/dist/chunk-DDM4CCYT.js.map +0 -1
- package/dist/chunk-E7UAOUMY.js +0 -75
- package/dist/chunk-E7UAOUMY.js.map +0 -1
- package/dist/chunk-F2IMUDXZ.js.map +0 -1
- package/dist/chunk-HEHYGYOX.js.map +0 -1
- package/dist/chunk-IM4QE42D.js.map +0 -1
- package/dist/chunk-MX64ZF6I.js.map +0 -1
- package/dist/chunk-SAUPYVLF.js.map +0 -1
- package/dist/chunk-THRPYOFK.js.map +0 -1
- package/dist/chunk-UCQSRW7Z.js.map +0 -1
- package/dist/chunk-VGZZXKBR.js.map +0 -1
- package/dist/chunk-YGPFYGA6.js.map +0 -1
- package/dist/chunk-YHCN776L.js.map +0 -1
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/request-deduplication.ts","../src/utils/google-places/loadGoogleMapsScript.ts","../src/utils/google-places/googlePlacesUtils.ts"],"sourcesContent":["/**\n * Request Deduplication Utility\n * @package @jmruthers/pace-core\n * @module Utils/RequestDeduplication\n * @since 2.0.0\n * \n * Provides request deduplication to prevent duplicate in-flight requests.\n * When multiple components request the same data simultaneously, only one\n * request is made and all callers share the same promise.\n */\n\nimport { createLogger } from './core/logger';\n\nconst log = createLogger('request-deduplication');\n\n/**\n * In-flight request cache\n * Key: request identifier (e.g., \"GET:table:filter:value\")\n * Value: Promise that resolves to the request result\n */\nconst inFlightRequests = new Map<string, Promise<any>>();\n\n/**\n * Generate a request key from request parameters\n * \n * @param method - HTTP method (GET, POST, etc.)\n * @param table - Table name\n * @param filters - Filter object\n * @param select - Select columns\n * @returns Request key string\n */\nexport function generateRequestKey(\n method: string,\n table: string,\n filters?: Record<string, any>,\n select?: string\n): string {\n const filterStr = filters ? JSON.stringify(filters) : '';\n const selectStr = select || '*';\n return `${method}:${table}:${filterStr}:${selectStr}`;\n}\n\n/**\n * Get or create a request\n * \n * If a request with the same key is already in-flight, returns the existing promise.\n * Otherwise, creates a new request and stores it for deduplication.\n * \n * @param key - Request key\n * @param requestFn - Function that performs the actual request\n * @returns Promise that resolves to the request result\n * \n * @example\n * ```ts\n * const data = await getOrCreateRequest(\n * 'GET:pace_person:{\"user_id\":\"123\"}',\n * async () => {\n * const { data } = await supabase\n * .from('pace_person')\n * .select('id, first_name')\n * .eq('user_id', '123')\n * .single();\n * return data;\n * }\n * );\n * ```\n */\nexport async function getOrCreateRequest<T>(\n key: string,\n requestFn: () => Promise<T>\n): Promise<T> {\n // Check if request is already in-flight\n const existingRequest = inFlightRequests.get(key);\n if (existingRequest) {\n log.debug(`Request deduplication: reusing in-flight request for ${key}`);\n return existingRequest as Promise<T>;\n }\n \n // Create new request\n log.debug(`Creating new request for ${key}`);\n const requestPromise = requestFn()\n .then((result) => {\n // Remove from in-flight cache after completion\n inFlightRequests.delete(key);\n return result;\n })\n .catch((error) => {\n // Remove from in-flight cache on error\n inFlightRequests.delete(key);\n throw error;\n });\n \n // Store in-flight request\n inFlightRequests.set(key, requestPromise);\n \n return requestPromise;\n}\n\n/**\n * Clear all in-flight requests\n * \n * Useful for cleanup or testing.\n */\nexport function clearInFlightRequests(): void {\n const count = inFlightRequests.size;\n inFlightRequests.clear();\n log.debug(`Cleared ${count} in-flight requests`);\n}\n\n/**\n * Get statistics about in-flight requests\n * \n * @returns Statistics object\n */\nexport function getInFlightRequestStats(): {\n count: number;\n keys: string[];\n} {\n return {\n count: inFlightRequests.size,\n keys: Array.from(inFlightRequests.keys()),\n };\n}\n\n/**\n * Supabase query wrapper with automatic deduplication\n * \n * Wraps a Supabase query to automatically deduplicate identical requests.\n * \n * @param supabase - Supabase client\n * @param table - Table name\n * @param filters - Filter object (e.g., { user_id: '123' })\n * @param select - Select columns (default: '*')\n * @param requestFn - Function that performs the query\n * @returns Promise that resolves to query result\n * \n * @example\n * ```ts\n * const person = await deduplicatedQuery(\n * supabase,\n * 'pace_person',\n * { user_id: userId },\n * 'id, first_name, last_name',\n * async () => {\n * const { data } = await supabase\n * .from('pace_person')\n * .select('id, first_name, last_name')\n * .eq('user_id', userId)\n * .single();\n * return data;\n * }\n * );\n * ```\n */\nexport async function deduplicatedQuery<T>(\n supabase: any,\n table: string,\n filters: Record<string, any>,\n select: string,\n requestFn: () => Promise<T>\n): Promise<T> {\n const key = generateRequestKey('GET', table, filters, select);\n return getOrCreateRequest(key, requestFn);\n}\n\n","/**\n * @file Google Maps Script Loader\n * @package @jmruthers/pace-core\n * @module Utils/GooglePlaces\n * @since 0.1.0\n *\n * Utility to dynamically load the Google Maps JavaScript API.\n * This is required because the REST API doesn't support CORS from browsers.\n */\n\n// Type definitions for Google Maps (minimal, just what we need)\ndeclare global {\n interface Window {\n google?: {\n maps: {\n places: {\n // New AutocompleteSuggestion API (recommended)\n AutocompleteSuggestion: {\n fetchAutocompleteSuggestions: (\n request: {\n input: string;\n includedRegionCodes?: string[];\n locationBias?: {\n circle?: {\n center: { latitude: number; longitude: number };\n radius: number;\n };\n };\n includedPrimaryTypes?: string[];\n languageCode?: string;\n }\n ) => Promise<{\n suggestions: Array<{\n placePrediction?: {\n placeId: string;\n text: {\n text: string;\n matches: Array<{\n endOffset: number;\n startOffset: number;\n }>;\n };\n structuredFormat?: {\n mainText: { text: string };\n secondaryText: { text: string };\n };\n };\n }>;\n }>;\n };\n // Legacy AutocompleteService (deprecated but still works)\n AutocompleteService: new () => {\n getPlacePredictions: (\n request: {\n input: string;\n componentRestrictions?: { country: string | string[] };\n location?: { lat: () => number; lng: () => number };\n radius?: number;\n types?: string[];\n language?: string;\n },\n callback: (\n predictions: Array<{\n description: string;\n place_id: string;\n structured_formatting: {\n main_text: string;\n secondary_text: string;\n };\n }> | null,\n status: string\n ) => void\n ) => void;\n };\n PlacesService: new (element: HTMLElement) => {\n getDetails: (\n request: { placeId: string; fields?: string[] },\n callback: (\n place: {\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n } | null,\n status: string\n ) => void\n ) => void;\n };\n PlacesServiceStatus: {\n OK: string;\n ZERO_RESULTS: string;\n NOT_FOUND: string;\n REQUEST_DENIED: string;\n INVALID_REQUEST: string;\n OVER_QUERY_LIMIT: string;\n };\n };\n LatLng: new (lat: number, lng: number) => { lat: () => number; lng: () => number };\n };\n };\n }\n}\n\n/**\n * Load Google Maps JavaScript API script\n * @param apiKey - Google Places API key\n * @param libraries - Comma-separated list of libraries to load (default: 'places')\n * @returns Promise that resolves when the script is loaded\n */\nexport function loadGoogleMapsScript(\n apiKey: string,\n libraries: string = 'places'\n): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if script is already loaded\n if (window.google && window.google.maps && window.google.maps.places) {\n resolve();\n return;\n }\n\n // Check if script is already being loaded\n const existingScript = document.querySelector(\n `script[src*=\"maps.googleapis.com/maps/api/js\"]`\n );\n if (existingScript) {\n // Wait for existing script to load\n existingScript.addEventListener('load', () => {\n // Wait for the library to initialize with multiple retries\n let attempts = 0;\n const maxAttempts = 20; // 2 seconds total\n \n const checkPlaces = () => {\n if (window.google?.maps?.places) {\n resolve();\n } else if (attempts < maxAttempts) {\n attempts++;\n setTimeout(checkPlaces, 100);\n } else {\n reject(new Error('Google Maps script loaded but Places library not available. Make sure the Places API is enabled in your Google Cloud Console.'));\n }\n };\n \n checkPlaces();\n });\n existingScript.addEventListener('error', () => {\n reject(new Error('Failed to load Google Maps script'));\n });\n return;\n }\n\n // Create and load script\n const script = document.createElement('script');\n script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=${libraries}&loading=async`;\n script.async = true;\n script.defer = true;\n\n script.onload = () => {\n // Wait for the library to initialize with multiple retries\n let attempts = 0;\n const maxAttempts = 20; // 2 seconds total (20 * 100ms)\n \n const checkPlaces = () => {\n if (window.google?.maps?.places) {\n resolve();\n } else if (attempts < maxAttempts) {\n attempts++;\n setTimeout(checkPlaces, 100);\n } else {\n // Check if google.maps exists but places doesn't\n if (window.google?.maps && !window.google.maps.places) {\n reject(new Error('Google Maps loaded but Places library not available. Make sure the Places API is enabled in your Google Cloud Console and the \"places\" library is included in the script URL.'));\n } else if (!window.google) {\n reject(new Error('Google Maps script loaded but google object not available. Check your API key and network connection.'));\n } else {\n reject(new Error('Google Maps script loaded but Places library not available after multiple attempts. Make sure the Places API is enabled in your Google Cloud Console.'));\n }\n }\n };\n \n // Start checking immediately, then retry if needed\n checkPlaces();\n };\n\n script.onerror = () => {\n reject(new Error('Failed to load Google Maps script'));\n };\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Check if Google Maps is already loaded\n */\nexport function isGoogleMapsLoaded(): boolean {\n return !!(window.google && window.google.maps && window.google.maps.places);\n}\n\n","/**\n * @file Google Places API Utilities\n * @package @jmruthers/pace-core\n * @module Utils/GooglePlaces\n * @since 0.1.0\n *\n * Utility functions for interacting with Google Places API.\n * Uses the Google Maps JavaScript API to avoid CORS issues.\n *\n * Features:\n * - Places Autocomplete Service integration\n * - Places Service integration\n * - Address component parsing\n * - Error handling\n * - Request deduplication\n */\n\nimport { getOrCreateRequest } from '../request-deduplication';\nimport { createLogger } from '../core/logger';\nimport { loadGoogleMapsScript, isGoogleMapsLoaded } from './loadGoogleMapsScript';\nimport type {\n GooglePlaceAutocompletePrediction,\n ParsedAddress,\n AutocompleteOptions,\n} from './types';\n\nconst log = createLogger('google-places');\n\n// Google Maps types are defined in loadGoogleMapsScript.ts\n\n/**\n * Fetch place autocomplete predictions using Google Maps JavaScript API\n *\n * @param query - Search query string\n * @param apiKey - Google Places API key\n * @param options - Optional autocomplete options\n * @returns Promise resolving to array of predictions\n *\n * @example\n * ```ts\n * const predictions = await fetchPlaceAutocomplete(\n * '123 Main St',\n * 'your-api-key',\n * { components: 'country:au' }\n * );\n * ```\n */\nexport async function fetchPlaceAutocomplete(\n query: string,\n apiKey: string,\n options?: AutocompleteOptions\n): Promise<GooglePlaceAutocompletePrediction[]> {\n if (!query.trim()) {\n return [];\n }\n\n if (!apiKey) {\n throw new Error('Google Places API key is required');\n }\n\n // Ensure Google Maps script is loaded\n if (!isGoogleMapsLoaded()) {\n await loadGoogleMapsScript(apiKey, 'places');\n }\n\n const requestKey = `google-places-autocomplete:${query}:${JSON.stringify(options || {})}`;\n\n return getOrCreateRequest(requestKey, async () => {\n try {\n log.debug(`Fetching autocomplete for query: ${query}`);\n\n if (!window.google?.maps?.places) {\n throw new Error('Google Maps Places library not available');\n }\n\n // Try to use the new AutocompleteSuggestion API first, fallback to legacy AutocompleteService\n const useNewAPI = window.google.maps.places.AutocompleteSuggestion !== undefined;\n \n if (useNewAPI) {\n // Use new AutocompleteSuggestion API\n const request: {\n input: string;\n includedRegionCodes?: string[];\n locationBias?: {\n circle?: {\n center: { latitude: number; longitude: number };\n radius: number;\n };\n };\n includedPrimaryTypes?: string[];\n languageCode?: string;\n } = {\n input: query.trim(),\n };\n\n // Parse components option (e.g., \"country:au\" -> [\"au\"])\n if (options?.components) {\n const componentParts = options.components.split('|');\n const countries: string[] = [];\n\n componentParts.forEach((part) => {\n const [key, value] = part.split(':');\n if (key === 'country') {\n countries.push(...value.split(',').map(c => c.toUpperCase()));\n }\n });\n\n if (countries.length > 0) {\n request.includedRegionCodes = countries;\n }\n }\n\n if (options?.location && options?.radius) {\n const [lat, lng] = options.location.split(',').map(Number);\n request.locationBias = {\n circle: {\n center: { latitude: lat, longitude: lng },\n radius: options.radius,\n },\n };\n }\n\n if (options?.language) {\n request.languageCode = options.language;\n }\n\n // Call new API\n return new Promise<GooglePlaceAutocompletePrediction[]>((resolve, reject) => {\n window.google!.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request)\n .then((response) => {\n if (response.suggestions && response.suggestions.length > 0) {\n const result: GooglePlaceAutocompletePrediction[] = response.suggestions\n .filter(s => s.placePrediction)\n .map((s) => ({\n description: s.placePrediction!.text.text,\n place_id: s.placePrediction!.placeId,\n structured_formatting: {\n main_text: s.placePrediction!.structuredFormat?.mainText?.text || s.placePrediction!.text.text,\n secondary_text: s.placePrediction!.structuredFormat?.secondaryText?.text || '',\n },\n }));\n log.debug(`Received ${result.length} predictions (new API)`);\n resolve(result);\n } else {\n log.debug('No results found (new API)');\n resolve([]);\n }\n })\n .catch((error) => {\n log.error('Autocomplete fetch failed (new API):', error);\n reject(new Error(`Failed to fetch autocomplete predictions: ${error.message || 'Unknown error'}`));\n });\n });\n }\n\n // Fallback to legacy AutocompleteService\n const autocompleteService = new window.google.maps.places.AutocompleteService();\n\n // Build request\n const request: {\n input: string;\n componentRestrictions?: { country: string | string[] };\n location?: { lat: () => number; lng: () => number };\n radius?: number;\n types?: string[];\n language?: string;\n } = {\n input: query.trim(),\n };\n\n // Parse components option (e.g., \"country:au\" -> { country: \"AU\" })\n if (options?.components) {\n const componentParts = options.components.split('|');\n const restrictions: { country?: string[] } = {};\n const countries: string[] = [];\n\n componentParts.forEach((part) => {\n const [key, value] = part.split(':');\n if (key === 'country') {\n // Convert to uppercase for consistency with Google Maps API\n countries.push(...value.split(',').map(c => c.toUpperCase()));\n }\n });\n\n if (countries.length > 0) {\n request.componentRestrictions = { country: countries.length === 1 ? countries[0] : countries };\n }\n }\n\n if (options?.location) {\n const [lat, lng] = options.location.split(',').map(Number);\n if (window.google?.maps?.LatLng) {\n request.location = new window.google.maps.LatLng(lat, lng);\n }\n }\n\n if (options?.radius) {\n request.radius = options.radius;\n }\n\n if (options?.types) {\n request.types = [options.types];\n }\n\n if (options?.language) {\n request.language = options.language;\n }\n\n // Call AutocompleteService\n return new Promise<GooglePlaceAutocompletePrediction[]>((resolve, reject) => {\n autocompleteService.getPlacePredictions(request, (predictions, status) => {\n if (status === 'OK' && predictions) {\n log.debug(`Received ${predictions.length} predictions`);\n // Convert to our format\n const result: GooglePlaceAutocompletePrediction[] = predictions.map((pred) => ({\n description: pred.description,\n place_id: pred.place_id,\n structured_formatting: {\n main_text: pred.structured_formatting.main_text,\n secondary_text: pred.structured_formatting.secondary_text,\n },\n }));\n resolve(result);\n } else if (status === 'ZERO_RESULTS') {\n log.debug('No results found');\n resolve([]);\n } else {\n const errorMsg = `Google Places API error: ${status}`;\n log.error('Autocomplete fetch failed:', errorMsg);\n reject(new Error(errorMsg));\n }\n });\n });\n } catch (error) {\n if (error instanceof Error) {\n log.error('Autocomplete fetch failed:', error.message);\n throw error;\n }\n log.error('Autocomplete fetch failed: Unknown error');\n throw new Error('Failed to fetch autocomplete predictions');\n }\n });\n}\n\n/**\n * Fetch place details from Google Places API\n *\n * @param placeId - Google Place ID\n * @param apiKey - Google Places API key\n * @returns Promise resolving to place details\n *\n * @example\n * ```ts\n * const place = await fetchPlaceDetails('ChIJ...', 'your-api-key');\n * ```\n */\nexport async function fetchPlaceDetails(\n placeId: string,\n apiKey: string\n): Promise<{\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n}> {\n if (!placeId) {\n throw new Error('Place ID is required');\n }\n\n if (!apiKey) {\n throw new Error('Google Places API key is required');\n }\n\n // Ensure Google Maps script is loaded\n if (!isGoogleMapsLoaded()) {\n await loadGoogleMapsScript(apiKey, 'places');\n }\n\n const requestKey = `google-places-details:${placeId}`;\n\n return getOrCreateRequest(requestKey, async () => {\n try {\n log.debug(`Fetching place details for place_id: ${placeId}`);\n\n if (!window.google?.maps?.places) {\n throw new Error('Google Maps Places library not available');\n }\n\n // Create a dummy element for PlacesService (it needs an element but we don't use it)\n const dummyElement = document.createElement('div');\n const placesService = new window.google.maps.places.PlacesService(dummyElement);\n\n // Call getDetails\n return new Promise<{\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n }>((resolve, reject) => {\n placesService.getDetails(\n {\n placeId: placeId,\n fields: ['place_id', 'formatted_address', 'address_components', 'geometry'],\n },\n (place, status) => {\n if (status === 'OK' && place) {\n log.debug('Place details fetched successfully');\n resolve(place as any);\n } else if (status === 'NOT_FOUND') {\n log.error('Place not found:', placeId);\n reject(new Error('Place not found'));\n } else {\n const errorMsg = `Failed to fetch place details: ${status}`;\n log.error('Place details fetch failed:', errorMsg);\n reject(new Error(errorMsg));\n }\n }\n );\n });\n } catch (error) {\n if (error instanceof Error) {\n log.error('Place details fetch failed:', error.message);\n throw error;\n }\n log.error('Place details fetch failed: Unknown error');\n throw new Error('Failed to fetch place details');\n }\n });\n}\n\n/**\n * Parse address components from Google Places API response\n *\n * @param components - Array of address components from Google API\n * @returns Parsed address components\n */\nexport function parseAddressComponents(\n components: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }> | undefined\n): {\n street_number: string | null;\n route: string | null;\n suburb: string | null;\n state: string | null;\n postcode: string | null;\n country: string | null;\n} {\n if (!components || components.length === 0) {\n return {\n street_number: null,\n route: null,\n suburb: null,\n state: null,\n postcode: null,\n country: null,\n };\n }\n\n const result = {\n street_number: null as string | null,\n route: null as string | null,\n suburb: null as string | null,\n state: null as string | null,\n postcode: null as string | null,\n country: null as string | null,\n };\n\n for (const component of components) {\n const types = component.types || [];\n\n if (types.includes('street_number')) {\n result.street_number = component.long_name;\n } else if (types.includes('route')) {\n result.route = component.long_name;\n } else if (types.includes('locality') || types.includes('sublocality')) {\n result.suburb = component.long_name;\n } else if (types.includes('administrative_area_level_1')) {\n result.state = component.short_name;\n } else if (types.includes('postal_code')) {\n result.postcode = component.long_name;\n } else if (types.includes('country')) {\n result.country = component.short_name;\n }\n }\n\n return result;\n}\n\n/**\n * Create parsed address from Google Places API place result\n *\n * @param place - Place result from Google Places Details API\n * @returns Parsed address matching pace_address table structure\n */\nexport function createAddressFromPlaceResult(\n place: {\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n }\n): ParsedAddress {\n const components = parseAddressComponents(place.address_components || []);\n\n return {\n place_id: place.place_id,\n full_address: place.formatted_address || null,\n street_number: components.street_number,\n route: components.route,\n suburb: components.suburb,\n state: components.state,\n postcode: components.postcode,\n country: components.country,\n lat: place.geometry?.location?.lat() ?? null,\n lng: place.geometry?.location?.lng() ?? null,\n };\n}\n\n/**\n * Get full address details by place_id\n * Useful for retrieving address from stored place_id without autocomplete search\n *\n * @param placeId - Google Place ID\n * @param apiKey - Google Places API key\n * @returns Promise resolving to parsed address\n *\n * @example\n * ```ts\n * const address = await getAddressByPlaceId('ChIJ...', 'your-api-key');\n * // Returns: { place_id: 'ChIJ...', full_address: '...', ... }\n * ```\n */\nexport async function getAddressByPlaceId(\n placeId: string,\n apiKey: string\n): Promise<ParsedAddress | null> {\n try {\n const place = await fetchPlaceDetails(placeId, apiKey);\n return createAddressFromPlaceResult(place);\n } catch (error) {\n log.error('Failed to get address by place_id:', error);\n return null;\n }\n}\n\n"],"mappings":";;;;;AAaA,IAAM,MAAM,aAAa,uBAAuB;AAOhD,IAAM,mBAAmB,oBAAI,IAA0B;AAWhD,SAAS,mBACd,QACA,OACA,SACA,QACQ;AACR,QAAM,YAAY,UAAU,KAAK,UAAU,OAAO,IAAI;AACtD,QAAM,YAAY,UAAU;AAC5B,SAAO,GAAG,MAAM,IAAI,KAAK,IAAI,SAAS,IAAI,SAAS;AACrD;AA2BA,eAAsB,mBACpB,KACA,WACY;AAEZ,QAAM,kBAAkB,iBAAiB,IAAI,GAAG;AAChD,MAAI,iBAAiB;AACnB,QAAI,MAAM,wDAAwD,GAAG,EAAE;AACvE,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,4BAA4B,GAAG,EAAE;AAC3C,QAAM,iBAAiB,UAAU,EAC9B,KAAK,CAAC,WAAW;AAEhB,qBAAiB,OAAO,GAAG;AAC3B,WAAO;AAAA,EACT,CAAC,EACA,MAAM,CAAC,UAAU;AAEhB,qBAAiB,OAAO,GAAG;AAC3B,UAAM;AAAA,EACR,CAAC;AAGH,mBAAiB,IAAI,KAAK,cAAc;AAExC,SAAO;AACT;AAOO,SAAS,wBAA8B;AAC5C,QAAM,QAAQ,iBAAiB;AAC/B,mBAAiB,MAAM;AACvB,MAAI,MAAM,WAAW,KAAK,qBAAqB;AACjD;AAOO,SAAS,0BAGd;AACA,SAAO;AAAA,IACL,OAAO,iBAAiB;AAAA,IACxB,MAAM,MAAM,KAAK,iBAAiB,KAAK,CAAC;AAAA,EAC1C;AACF;AAgCA,eAAsB,kBACpB,UACA,OACA,SACA,QACA,WACY;AACZ,QAAM,MAAM,mBAAmB,OAAO,OAAO,SAAS,MAAM;AAC5D,SAAO,mBAAmB,KAAK,SAAS;AAC1C;;;AC7CO,SAAS,qBACd,QACA,YAAoB,UACL;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,QAAI,OAAO,UAAU,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAK,QAAQ;AACpE,cAAQ;AACR;AAAA,IACF;AAGA,UAAM,iBAAiB,SAAS;AAAA,MAC9B;AAAA,IACF;AACA,QAAI,gBAAgB;AAElB,qBAAe,iBAAiB,QAAQ,MAAM;AAE5C,YAAI,WAAW;AACf,cAAM,cAAc;AAEpB,cAAM,cAAc,MAAM;AACxB,cAAI,OAAO,QAAQ,MAAM,QAAQ;AAC/B,oBAAQ;AAAA,UACV,WAAW,WAAW,aAAa;AACjC;AACA,uBAAW,aAAa,GAAG;AAAA,UAC7B,OAAO;AACL,mBAAO,IAAI,MAAM,+HAA+H,CAAC;AAAA,UACnJ;AAAA,QACF;AAEA,oBAAY;AAAA,MACd,CAAC;AACD,qBAAe,iBAAiB,SAAS,MAAM;AAC7C,eAAO,IAAI,MAAM,mCAAmC,CAAC;AAAA,MACvD,CAAC;AACD;AAAA,IACF;AAGA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,MAAM,+CAA+C,MAAM,cAAc,SAAS;AACzF,WAAO,QAAQ;AACf,WAAO,QAAQ;AAEf,WAAO,SAAS,MAAM;AAEpB,UAAI,WAAW;AACf,YAAM,cAAc;AAEpB,YAAM,cAAc,MAAM;AACxB,YAAI,OAAO,QAAQ,MAAM,QAAQ;AAC/B,kBAAQ;AAAA,QACV,WAAW,WAAW,aAAa;AACjC;AACA,qBAAW,aAAa,GAAG;AAAA,QAC7B,OAAO;AAEL,cAAI,OAAO,QAAQ,QAAQ,CAAC,OAAO,OAAO,KAAK,QAAQ;AACrD,mBAAO,IAAI,MAAM,+KAA+K,CAAC;AAAA,UACnM,WAAW,CAAC,OAAO,QAAQ;AACzB,mBAAO,IAAI,MAAM,uGAAuG,CAAC;AAAA,UAC3H,OAAO;AACL,mBAAO,IAAI,MAAM,uJAAuJ,CAAC;AAAA,UAC3K;AAAA,QACF;AAAA,MACF;AAGA,kBAAY;AAAA,IACd;AAEA,WAAO,UAAU,MAAM;AACrB,aAAO,IAAI,MAAM,mCAAmC,CAAC;AAAA,IACvD;AAEA,aAAS,KAAK,YAAY,MAAM;AAAA,EAClC,CAAC;AACH;AAKO,SAAS,qBAA8B;AAC5C,SAAO,CAAC,EAAE,OAAO,UAAU,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAK;AACtE;;;ACnLA,IAAMA,OAAM,aAAa,eAAe;AAqBxC,eAAsB,uBACpB,OACA,QACA,SAC8C;AAC9C,MAAI,CAAC,MAAM,KAAK,GAAG;AACjB,WAAO,CAAC;AAAA,EACV;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAGA,MAAI,CAAC,mBAAmB,GAAG;AACzB,UAAM,qBAAqB,QAAQ,QAAQ;AAAA,EAC7C;AAEA,QAAM,aAAa,8BAA8B,KAAK,IAAI,KAAK,UAAU,WAAW,CAAC,CAAC,CAAC;AAEvF,SAAO,mBAAmB,YAAY,YAAY;AAChD,QAAI;AACF,MAAAA,KAAI,MAAM,oCAAoC,KAAK,EAAE;AAErD,UAAI,CAAC,OAAO,QAAQ,MAAM,QAAQ;AAChC,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC5D;AAGA,YAAM,YAAY,OAAO,OAAO,KAAK,OAAO,2BAA2B;AAEvE,UAAI,WAAW;AAEb,cAAMC,WAWF;AAAA,UACF,OAAO,MAAM,KAAK;AAAA,QACpB;AAGA,YAAI,SAAS,YAAY;AACvB,gBAAM,iBAAiB,QAAQ,WAAW,MAAM,GAAG;AACnD,gBAAM,YAAsB,CAAC;AAE7B,yBAAe,QAAQ,CAAC,SAAS;AAC/B,kBAAM,CAAC,KAAK,KAAK,IAAI,KAAK,MAAM,GAAG;AACnC,gBAAI,QAAQ,WAAW;AACrB,wBAAU,KAAK,GAAG,MAAM,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,YAAY,CAAC,CAAC;AAAA,YAC9D;AAAA,UACF,CAAC;AAED,cAAI,UAAU,SAAS,GAAG;AACxB,YAAAA,SAAQ,sBAAsB;AAAA,UAChC;AAAA,QACF;AAEA,YAAI,SAAS,YAAY,SAAS,QAAQ;AACxC,gBAAM,CAAC,KAAK,GAAG,IAAI,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,MAAM;AACzD,UAAAA,SAAQ,eAAe;AAAA,YACrB,QAAQ;AAAA,cACN,QAAQ,EAAE,UAAU,KAAK,WAAW,IAAI;AAAA,cACxC,QAAQ,QAAQ;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AAEA,YAAI,SAAS,UAAU;AACrB,UAAAA,SAAQ,eAAe,QAAQ;AAAA,QACjC;AAGA,eAAO,IAAI,QAA6C,CAAC,SAAS,WAAW;AAC3E,iBAAO,OAAQ,KAAK,OAAO,uBAAuB,6BAA6BA,QAAO,EACnF,KAAK,CAAC,aAAa;AAClB,gBAAI,SAAS,eAAe,SAAS,YAAY,SAAS,GAAG;AAC3D,oBAAM,SAA8C,SAAS,YAC1D,OAAO,OAAK,EAAE,eAAe,EAC7B,IAAI,CAAC,OAAO;AAAA,gBACX,aAAa,EAAE,gBAAiB,KAAK;AAAA,gBACrC,UAAU,EAAE,gBAAiB;AAAA,gBAC7B,uBAAuB;AAAA,kBACrB,WAAW,EAAE,gBAAiB,kBAAkB,UAAU,QAAQ,EAAE,gBAAiB,KAAK;AAAA,kBAC1F,gBAAgB,EAAE,gBAAiB,kBAAkB,eAAe,QAAQ;AAAA,gBAC9E;AAAA,cACF,EAAE;AACJ,cAAAD,KAAI,MAAM,YAAY,OAAO,MAAM,wBAAwB;AAC3D,sBAAQ,MAAM;AAAA,YAChB,OAAO;AACL,cAAAA,KAAI,MAAM,4BAA4B;AACtC,sBAAQ,CAAC,CAAC;AAAA,YACZ;AAAA,UACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,YAAAA,KAAI,MAAM,wCAAwC,KAAK;AACvD,mBAAO,IAAI,MAAM,6CAA6C,MAAM,WAAW,eAAe,EAAE,CAAC;AAAA,UACnG,CAAC;AAAA,QACL,CAAC;AAAA,MACH;AAGA,YAAM,sBAAsB,IAAI,OAAO,OAAO,KAAK,OAAO,oBAAoB;AAG9E,YAAM,UAOF;AAAA,QACF,OAAO,MAAM,KAAK;AAAA,MACpB;AAGA,UAAI,SAAS,YAAY;AACvB,cAAM,iBAAiB,QAAQ,WAAW,MAAM,GAAG;AACnD,cAAM,eAAuC,CAAC;AAC9C,cAAM,YAAsB,CAAC;AAE7B,uBAAe,QAAQ,CAAC,SAAS;AAC/B,gBAAM,CAAC,KAAK,KAAK,IAAI,KAAK,MAAM,GAAG;AACnC,cAAI,QAAQ,WAAW;AAErB,sBAAU,KAAK,GAAG,MAAM,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,YAAY,CAAC,CAAC;AAAA,UAC9D;AAAA,QACF,CAAC;AAED,YAAI,UAAU,SAAS,GAAG;AACxB,kBAAQ,wBAAwB,EAAE,SAAS,UAAU,WAAW,IAAI,UAAU,CAAC,IAAI,UAAU;AAAA,QAC/F;AAAA,MACF;AAEA,UAAI,SAAS,UAAU;AACrB,cAAM,CAAC,KAAK,GAAG,IAAI,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,MAAM;AACzD,YAAI,OAAO,QAAQ,MAAM,QAAQ;AAC/B,kBAAQ,WAAW,IAAI,OAAO,OAAO,KAAK,OAAO,KAAK,GAAG;AAAA,QAC3D;AAAA,MACF;AAEA,UAAI,SAAS,QAAQ;AACnB,gBAAQ,SAAS,QAAQ;AAAA,MAC3B;AAEA,UAAI,SAAS,OAAO;AAClB,gBAAQ,QAAQ,CAAC,QAAQ,KAAK;AAAA,MAChC;AAEA,UAAI,SAAS,UAAU;AACrB,gBAAQ,WAAW,QAAQ;AAAA,MAC7B;AAGA,aAAO,IAAI,QAA6C,CAAC,SAAS,WAAW;AAC3E,4BAAoB,oBAAoB,SAAS,CAAC,aAAa,WAAW;AACxE,cAAI,WAAW,QAAQ,aAAa;AAClC,YAAAA,KAAI,MAAM,YAAY,YAAY,MAAM,cAAc;AAEtD,kBAAM,SAA8C,YAAY,IAAI,CAAC,UAAU;AAAA,cAC7E,aAAa,KAAK;AAAA,cAClB,UAAU,KAAK;AAAA,cACf,uBAAuB;AAAA,gBACrB,WAAW,KAAK,sBAAsB;AAAA,gBACtC,gBAAgB,KAAK,sBAAsB;AAAA,cAC7C;AAAA,YACF,EAAE;AACF,oBAAQ,MAAM;AAAA,UAChB,WAAW,WAAW,gBAAgB;AACpC,YAAAA,KAAI,MAAM,kBAAkB;AAC5B,oBAAQ,CAAC,CAAC;AAAA,UACZ,OAAO;AACL,kBAAM,WAAW,4BAA4B,MAAM;AACnD,YAAAA,KAAI,MAAM,8BAA8B,QAAQ;AAChD,mBAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,UAC5B;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,OAAO;AAC1B,QAAAA,KAAI,MAAM,8BAA8B,MAAM,OAAO;AACrD,cAAM;AAAA,MACR;AACA,MAAAA,KAAI,MAAM,0CAA0C;AACpD,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAAA,EACF,CAAC;AACH;AAcA,eAAsB,kBACpB,SACA,QAeC;AACD,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAGA,MAAI,CAAC,mBAAmB,GAAG;AACzB,UAAM,qBAAqB,QAAQ,QAAQ;AAAA,EAC7C;AAEA,QAAM,aAAa,yBAAyB,OAAO;AAEnD,SAAO,mBAAmB,YAAY,YAAY;AAChD,QAAI;AACF,MAAAA,KAAI,MAAM,wCAAwC,OAAO,EAAE;AAE3D,UAAI,CAAC,OAAO,QAAQ,MAAM,QAAQ;AAChC,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC5D;AAGA,YAAM,eAAe,SAAS,cAAc,KAAK;AACjD,YAAM,gBAAgB,IAAI,OAAO,OAAO,KAAK,OAAO,cAAc,YAAY;AAG9E,aAAO,IAAI,QAcR,CAAC,SAAS,WAAW;AACtB,sBAAc;AAAA,UACZ;AAAA,YACE;AAAA,YACA,QAAQ,CAAC,YAAY,qBAAqB,sBAAsB,UAAU;AAAA,UAC5E;AAAA,UACA,CAAC,OAAO,WAAW;AACjB,gBAAI,WAAW,QAAQ,OAAO;AAC5B,cAAAA,KAAI,MAAM,oCAAoC;AAC9C,sBAAQ,KAAY;AAAA,YACtB,WAAW,WAAW,aAAa;AACjC,cAAAA,KAAI,MAAM,oBAAoB,OAAO;AACrC,qBAAO,IAAI,MAAM,iBAAiB,CAAC;AAAA,YACrC,OAAO;AACL,oBAAM,WAAW,kCAAkC,MAAM;AACzD,cAAAA,KAAI,MAAM,+BAA+B,QAAQ;AACjD,qBAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,YAC5B;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,OAAO;AAC1B,QAAAA,KAAI,MAAM,+BAA+B,MAAM,OAAO;AACtD,cAAM;AAAA,MACR;AACA,MAAAA,KAAI,MAAM,2CAA2C;AACrD,YAAM,IAAI,MAAM,+BAA+B;AAAA,IACjD;AAAA,EACF,CAAC;AACH;AAQO,SAAS,uBACd,YAYA;AACA,MAAI,CAAC,cAAc,WAAW,WAAW,GAAG;AAC1C,WAAO;AAAA,MACL,eAAe;AAAA,MACf,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,UAAU;AAAA,MACV,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,SAAS;AAAA,IACb,eAAe;AAAA,IACf,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,UAAU,SAAS,CAAC;AAElC,QAAI,MAAM,SAAS,eAAe,GAAG;AACnC,aAAO,gBAAgB,UAAU;AAAA,IACnC,WAAW,MAAM,SAAS,OAAO,GAAG;AAClC,aAAO,QAAQ,UAAU;AAAA,IAC3B,WAAW,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS,aAAa,GAAG;AACtE,aAAO,SAAS,UAAU;AAAA,IAC5B,WAAW,MAAM,SAAS,6BAA6B,GAAG;AACxD,aAAO,QAAQ,UAAU;AAAA,IAC3B,WAAW,MAAM,SAAS,aAAa,GAAG;AACxC,aAAO,WAAW,UAAU;AAAA,IAC9B,WAAW,MAAM,SAAS,SAAS,GAAG;AACpC,aAAO,UAAU,UAAU;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,6BACd,OAee;AACf,QAAM,aAAa,uBAAuB,MAAM,sBAAsB,CAAC,CAAC;AAExE,SAAO;AAAA,IACL,UAAU,MAAM;AAAA,IAChB,cAAc,MAAM,qBAAqB;AAAA,IACzC,eAAe,WAAW;AAAA,IAC1B,OAAO,WAAW;AAAA,IAClB,QAAQ,WAAW;AAAA,IACnB,OAAO,WAAW;AAAA,IAClB,UAAU,WAAW;AAAA,IACrB,SAAS,WAAW;AAAA,IACpB,KAAK,MAAM,UAAU,UAAU,IAAI,KAAK;AAAA,IACxC,KAAK,MAAM,UAAU,UAAU,IAAI,KAAK;AAAA,EAC1C;AACF;AAgBA,eAAsB,oBACpB,SACA,QAC+B;AAC/B,MAAI;AACF,UAAM,QAAQ,MAAM,kBAAkB,SAAS,MAAM;AACrD,WAAO,6BAA6B,KAAK;AAAA,EAC3C,SAAS,OAAO;AACd,IAAAA,KAAI,MAAM,sCAAsC,KAAK;AACrD,WAAO;AAAA,EACT;AACF;","names":["log","request"]}
|