@plumile/backoffice-react 0.1.143 → 0.1.144
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/lib/esm/auth/AuthRefreshNotice.js.map +1 -1
- package/lib/esm/auth/TotpQrCode.js.map +1 -1
- package/lib/esm/auth/authRefreshNotice.css.js +1 -1
- package/lib/esm/auth/login/AuthPanel.js.map +1 -1
- package/lib/esm/auth/login/EmailCapturePanel.js.map +1 -1
- package/lib/esm/auth/login/LoginFlow.js.map +1 -1
- package/lib/esm/auth/login/MethodChooser.js.map +1 -1
- package/lib/esm/auth/login/MfaChallengeForm.js.map +1 -1
- package/lib/esm/auth/login/OidcButtons.js.map +1 -1
- package/lib/esm/auth/login/PasskeyLoginForm.js.map +1 -1
- package/lib/esm/auth/login/PasswordLoginPanel.js.map +1 -1
- package/lib/esm/auth/login/loginPage.css.js +1 -1
- package/lib/esm/auth/login/loginPage.css.js.map +1 -1
- package/lib/esm/auth/login/synchronizeAuthStatusQuery.js.map +1 -1
- package/lib/esm/auth/pages/AcceptInvitationScreen.js.map +1 -1
- package/lib/esm/auth/pages/PasswordResetCompleteScreen.js.map +1 -1
- package/lib/esm/auth/pages/PasswordResetRequestScreen.js.map +1 -1
- package/lib/esm/auth/pages/VerifyEmailScreen.js.map +1 -1
- package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js +14 -14
- package/lib/esm/components/backoffice/actions/BackofficeEntityActionFormDialog.js.map +1 -1
- package/lib/esm/components/backoffice/actions/LazyBackofficeEntityActionFormDialog.js.map +1 -1
- package/lib/esm/components/backoffice/actions/backofficeEntityActionFormDialog.css.js +1 -1
- package/lib/esm/components/backoffice/actions/toastViewAction.js.map +1 -1
- package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js +1 -1
- package/lib/esm/components/backoffice/billing/BackofficeBillingUsageChart.js.map +1 -1
- package/lib/esm/components/backoffice/billing/backofficeBillingUsageChart.css.js +1 -1
- package/lib/esm/components/backoffice/columns/buildDataTableColumns.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailBadgeRow.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailErrorList.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailFlagTag.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailRelationLink.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailRelationList.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailRelationListBlock.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeDetailTaggedValue.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js +6 -6
- package/lib/esm/components/backoffice/detail/BackofficeEntitySummaryHeader.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeEnumLabel.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeLifecycleTimelineSection.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeReferenceValue.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeRelationsSummaryGrid.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeStatusGroup.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeStatusMetaBadge.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeTokenUsageBreakdown.js.map +1 -1
- package/lib/esm/components/backoffice/detail/BackofficeUsageCostBreakdown.js +13 -13
- package/lib/esm/components/backoffice/detail/BackofficeUsageCostBreakdown.js.map +1 -1
- package/lib/esm/components/backoffice/detail/backofficeDetailBadgeRow.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeDetailErrorList.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeDetailLayout.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeDetailRelationLink.css.js +2 -1
- package/lib/esm/components/backoffice/detail/backofficeDetailRelationList.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeEntitySummaryHeader.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeRelationsSummaryGrid.css.js +1 -1
- package/lib/esm/components/backoffice/detail/backofficeUsageCostBreakdown.css.js +1 -1
- package/lib/esm/components/backoffice/detail/createBackofficeEntityLinkProps.js.map +1 -1
- package/lib/esm/components/backoffice/detail/detailPayloadUtils.js.map +1 -1
- package/lib/esm/components/backoffice/errors/BackofficeErrorBoundary.js.map +1 -1
- package/lib/esm/components/backoffice/filters/BackofficeFilterAction.js.map +1 -1
- package/lib/esm/components/backoffice/filters/DeferredFilterSearchInput.js.map +1 -1
- package/lib/esm/components/backoffice/filters/EntityFilterValue.js.map +1 -1
- package/lib/esm/components/backoffice/filters/EntityIdFilterField.js +1 -1
- package/lib/esm/components/backoffice/filters/EntityIdFilterField.js.map +1 -1
- package/lib/esm/components/backoffice/filters/backofficeFilterAction.css.js +1 -1
- package/lib/esm/components/backoffice/filters/backofficeFilterAction.css.js.map +1 -1
- package/lib/esm/components/backoffice/filters/deferredFilterSearchInput.css.js +1 -1
- package/lib/esm/components/backoffice/filters/entityIdFilterField.css.js +1 -1
- package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js +5 -5
- package/lib/esm/components/backoffice/hub/BackofficeHubTemplate.js.map +1 -1
- package/lib/esm/components/backoffice/hub/backofficeHubTemplate.css.js +1 -1
- package/lib/esm/components/backoffice/layout/BackofficePermissionsContext.js.map +1 -1
- package/lib/esm/components/backoffice/layout/backofficeSidebarActions.css.js +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeRightPageLayout.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js +2 -2
- package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarBreadcrumb.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarPortal.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/BackofficeTopbarPortalContext.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/assertValidBreadcrumb.js.map +1 -1
- package/lib/esm/components/backoffice/layout/breadcrumb/backofficeTopbarBreadcrumb.css.js +1 -2
- package/lib/esm/components/backoffice/layout/breadcrumb/buildBreadcrumbs.js.map +1 -1
- package/lib/esm/components/backoffice/layout/buildSidebarSections.js.map +1 -1
- package/lib/esm/components/backoffice/layout/mapViewerToSidebarProfileView.js.map +1 -1
- package/lib/esm/components/backoffice/layout/sidebarUtils.js.map +1 -1
- package/lib/esm/components/backoffice/links/BackofficeInlineLink.js.map +1 -1
- package/lib/esm/components/backoffice/links/BackofficeLink.js.map +1 -1
- package/lib/esm/components/backoffice/links/BackofficeLinkContent.js +1 -1
- package/lib/esm/components/backoffice/links/BackofficeLinkContent.js.map +1 -1
- package/lib/esm/components/backoffice/links/BackofficeLinkLabel.js.map +1 -1
- package/lib/esm/components/backoffice/links/backofficeLink.css.js +1 -1
- package/lib/esm/components/backoffice/links/resolveBackofficeLink.js.map +1 -1
- package/lib/esm/components/backoffice/links/resolveBackofficeTargetIcon.js.map +1 -1
- package/lib/esm/components/backoffice/links/useBackofficeLink.js.map +1 -1
- package/lib/esm/components/backoffice/list/RowFlagsCell.css.js +1 -1
- package/lib/esm/components/backoffice/list/RowFlagsCell.js.map +1 -1
- package/lib/esm/components/backoffice/overview/BackofficeOverviewLayout.js.map +1 -1
- package/lib/esm/components/backoffice/overview/backofficeOverviewLayout.css.js +1 -1
- package/lib/esm/components/backoffice/overview/backofficeOverviewLayout.css.js.map +1 -1
- package/lib/esm/components/backoffice/pickers/EntityIdPickerDialog.js.map +1 -1
- package/lib/esm/components/backoffice/pickers/entityIdPickerDialog.css.js +1 -1
- package/lib/esm/components/backoffice/refs/BackofficeEntityIdRef.js.map +1 -1
- package/lib/esm/components/backoffice/refs/BackofficeEntityLink.js.map +1 -1
- package/lib/esm/components/backoffice/refs/BackofficeRelatedCountLink.js.map +1 -1
- package/lib/esm/components/backoffice/refs/backofficeEntityIdRef.css.js +1 -1
- package/lib/esm/components/backoffice/refs/backofficeRelatedCountLink.css.js +1 -1
- package/lib/esm/components/backoffice/routing/BackofficeContentBoundary.js.map +1 -1
- package/lib/esm/components/backoffice/routing/BackofficeContentError.js.map +1 -1
- package/lib/esm/components/backoffice/routing/BackofficeContentFallback.js.map +1 -1
- package/lib/esm/components/backoffice/routing/BackofficeRouteFallback.js.map +1 -1
- package/lib/esm/components/backoffice/routing/BackofficeRoutePendingBar.js.map +1 -1
- package/lib/esm/components/backoffice/routing/backofficeContentBoundary.css.js +1 -1
- package/lib/esm/components/backoffice/routing/backofficeContentError.css.js +1 -1
- package/lib/esm/components/backoffice/routing/backofficeContentFallback.css.js +1 -1
- package/lib/esm/components/backoffice/routing/backofficeRouteFallback.css.js +1 -1
- package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js +1 -1
- package/lib/esm/components/backoffice/routing/backofficeRoutePendingBar.css.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/BackofficeEntityDetailScaffold.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/BackofficeEntityListScaffold.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/BackofficeListFilterContext.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/BackofficeTabbedDetailShell.js.map +1 -1
- package/lib/esm/components/backoffice/scaffolds/backofficeEntityListScaffold.css.js +1 -1
- package/lib/esm/components/backoffice/scaffolds/backofficeTabbedDetailShell.css.js +1 -1
- package/lib/esm/components/backoffice/shared/BackofficeFilterableCell.js.map +1 -1
- package/lib/esm/components/backoffice/shared/BackofficeFormattedCurrency.js.map +1 -1
- package/lib/esm/components/backoffice/shared/BackofficeFormattedNumber.js.map +1 -1
- package/lib/esm/components/backoffice/shared/BackofficeInlineFilterRow.js.map +1 -1
- package/lib/esm/components/backoffice/shared/backofficeFilterableCell.css.js +5 -5
- package/lib/esm/components/backoffice/shared/backofficeFilterableCell.css.js.map +1 -1
- package/lib/esm/components/backoffice/shared/backofficeInlineFilterRow.css.js +1 -1
- package/lib/esm/components/backoffice/tools/BackofficeToolsDocPanel.js +1 -1
- package/lib/esm/components/backoffice/tools/BackofficeToolsDocPanel.js.map +1 -1
- package/lib/esm/components/backoffice/tools/BackofficeToolsErrorFallback.js.map +1 -1
- package/lib/esm/components/backoffice/tools/BackofficeToolsJsonForm.js.map +1 -1
- package/lib/esm/components/backoffice/tools/BackofficeToolsQueryBoundary.js.map +1 -1
- package/lib/esm/components/backoffice/tools/backofficeToolsDocPanel.css.js +1 -1
- package/lib/esm/components/backoffice/tools/backofficeToolsDocPanel.css.js.map +1 -1
- package/lib/esm/components/backoffice/tools/backofficeToolsForm.css.js +1 -1
- package/lib/esm/components/backoffice/tools/backofficeToolsJsonForm.css.js +1 -1
- package/lib/esm/components/backoffice/tools/parseToolJson.js.map +1 -1
- package/lib/esm/filters/filterHelpers.js.map +1 -1
- package/lib/esm/hooks/useAuth.js.map +1 -1
- package/lib/esm/hooks/useBackofficeAuth.js.map +1 -1
- package/lib/esm/hooks/useBackofficeInfiniteScrollSentinel.js.map +1 -1
- package/lib/esm/hooks/useBackofficeListRefetch.js.map +1 -1
- package/lib/esm/hooks/useBackofficeListUrlState.js.map +1 -1
- package/lib/esm/hooks/useBackofficeLoadMore.js.map +1 -1
- package/lib/esm/hooks/useBackofficeSessionAuth.js.map +1 -1
- package/lib/esm/hooks/useBackofficeSidebarPins.js.map +1 -1
- package/lib/esm/hooks/useConditionalSubscription.js.map +1 -1
- package/lib/esm/hooks/useCopyToClipboard.js.map +1 -1
- package/lib/esm/hooks/useInfiniteConnection.js.map +1 -1
- package/lib/esm/hooks/useRefetchNeededReload.js.map +1 -1
- package/lib/esm/hooks/useSidebarGroupCollapse.js.map +1 -1
- package/lib/esm/i18n/createI18nInstance.js.map +1 -1
- package/lib/esm/i18n/mergeResourceLanguages.js.map +1 -1
- package/lib/esm/i18n/resources.js.map +1 -1
- package/lib/esm/i18n/useBackofficeFormats.js.map +1 -1
- package/lib/esm/i18n/useBackofficeReactTranslation.js.map +1 -1
- package/lib/esm/i18n/useReviewStatusLabel.js.map +1 -1
- package/lib/esm/modules/base64.js.map +1 -1
- package/lib/esm/modules/formatFileSize.js.map +1 -1
- package/lib/esm/modules/webauthn.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/arrayLikeToArray.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/defineProperty.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/interopRequireDefault.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/iterableToArray.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/nonIterableSpread.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/objectSpread2.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/toConsumableArray.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/toPrimitive.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/toPropertyKey.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/typeof.js.map +1 -1
- package/lib/esm/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js.map +1 -1
- package/lib/esm/node_modules/@vanilla-extract/recipes/dist/createRuntimeFn-62c9670f.esm.js.map +1 -1
- package/lib/esm/node_modules/fbjs/lib/areEqual.js.map +1 -1
- package/lib/esm/node_modules/invariant/browser.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/index.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/lib/RelayMockPayloadGenerator.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/lib/RelayModernMockEnvironment.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/lib/RelayResolverTestUtils.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/lib/index.js.map +1 -1
- package/lib/esm/node_modules/relay-test-utils/lib/unwrapContainer.js.map +1 -1
- package/lib/esm/pages/BackofficeAcceptInvitationPage.js.map +1 -1
- package/lib/esm/pages/BackofficeDashboardPage.helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeDashboardPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailLayoutPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailPage.helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailPage.js +2 -2
- package/lib/esm/pages/BackofficeEntityDetailPage.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailPage.view-helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityDetailUnknownPageRedirect.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityListPage.helpers.js.map +1 -1
- package/lib/esm/pages/BackofficeEntityListPage.js.map +1 -1
- package/lib/esm/pages/BackofficeHubPage.js.map +1 -1
- package/lib/esm/pages/BackofficeLayoutPage.js.map +1 -1
- package/lib/esm/pages/BackofficeLoginPage.js.map +1 -1
- package/lib/esm/pages/BackofficePasswordResetCompletePage.js.map +1 -1
- package/lib/esm/pages/BackofficePasswordResetRequestPage.js.map +1 -1
- package/lib/esm/pages/BackofficeVerifyEmailPage.js.map +1 -1
- package/lib/esm/pages/backofficeDashboardPage.css.js +1 -1
- package/lib/esm/pages/backofficeEntityDetailPage.css.js +1 -1
- package/lib/esm/pages/backofficeEntityListPage.css.js +1 -1
- package/lib/esm/pages/detail/BackofficeEntityDetailLayoutContext.js.map +1 -1
- package/lib/esm/pages/detail/buildTabsItems.js.map +1 -1
- package/lib/esm/pages/detail/pageResolution.js.map +1 -1
- package/lib/esm/provider/BackofficeConfigContext.js.map +1 -1
- package/lib/esm/provider/BackofficeProvider.js.map +1 -1
- package/lib/esm/provider/dashboardRegistrations.js.map +1 -1
- package/lib/esm/provider/entityRegistry.js.map +1 -1
- package/lib/esm/provider/lazyValue.js.map +1 -1
- package/lib/esm/provider/useBackofficeEntityLoader.js.map +1 -1
- package/lib/esm/provider/useBackofficeLazyValue.js.map +1 -1
- package/lib/esm/relay/RelayProvider.js.map +1 -1
- package/lib/esm/relay/connectionUtils.js.map +1 -1
- package/lib/esm/relay/createInlineReader.js.map +1 -1
- package/lib/esm/relay/envHelpers.js.map +1 -1
- package/lib/esm/relay/environment.js.map +1 -1
- package/lib/esm/relay/mutationResult.js.map +1 -1
- package/lib/esm/router/backofficeAuthPaths.js.map +1 -1
- package/lib/esm/router/createBackofficeRoutes.js.map +1 -1
- package/lib/esm/storybook/relay/RelayStory.css.js +1 -1
- package/lib/esm/storybook/relay/RelayStory.js.map +1 -1
- package/lib/esm/storybook/relay/mockResolvers.js.map +1 -1
- package/lib/esm/style.css +1 -1
- package/lib/esm/subscriptions/useCursorResumableSubscription.js.map +1 -1
- package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts +1 -1
- package/lib/types/components/backoffice/errors/BackofficeErrorBoundary.stories.d.ts.map +1 -1
- package/lib/types/components/backoffice/overview/backofficeOverviewLayout.css.d.ts.map +1 -1
- package/lib/types/components/backoffice/tools/backofficeToolsDocPanel.css.d.ts.map +1 -1
- package/package.json +16 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.js","names":[],"sources":["../../../src/hooks/useAuth.ts"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useCallback, useState } from 'react';\n\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\n\nimport { resetRelayStore } from '../relay/environment.js';\nimport type { PayloadError } from 'relay-runtime';\n\nimport type {\n AuthMethod,\n LoginNextStep,\n MfaLevel,\n} from '../modules/sharedSchemaTypes.js';\nimport {\n base64UrlToBuffer,\n bufferToBase64Url,\n parseSignCount,\n} from '../modules/webauthn.js';\n\nexport type AuthPayload = {\n authMethod: AuthMethod | null | undefined;\n challengeToken: string | null | undefined;\n loggedInUser: { id: string } | null | undefined;\n mfaLevel: MfaLevel | null | undefined;\n nextStep: LoginNextStep | null | undefined;\n};\n\ntype LoginErrorReason =\n | 'INVALID_CREDENTIALS'\n | 'ACCOUNT_LOCKED'\n | 'RATE_LIMITED'\n | 'INTERNAL_ERROR';\n\ntype LogoutErrorReason =\n | 'UNAUTHENTICATED'\n | 'SESSION_NOT_FOUND'\n | 'INTERNAL_ERROR';\n\ntype BeginAuthenticationErrorReason = 'INVALID_EMAIL' | 'INTERNAL_ERROR';\n\ntype BeginPasskeyLoginErrorReason =\n | 'INVALID_EMAIL'\n | 'PASSKEY_NOT_FOUND'\n | 'PASSKEY_NOT_SUPPORTED'\n | 'INTERNAL_ERROR';\n\ntype FinishPasskeyLoginErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_ASSERTION'\n | 'INTERNAL_ERROR';\n\ntype CompleteMfaErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_CODE'\n | 'TOO_MANY_ATTEMPTS'\n | 'INTERNAL_ERROR';\n\ntype AcceptInvitationErrorReason =\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'ALREADY_ACCEPTED'\n | 'PASSWORD_MISMATCH'\n | 'PASSWORD_POLICY_VIOLATION'\n | 'RATE_LIMITED'\n | 'EMAIL_MISMATCH'\n | 'INTERNAL_ERROR';\n\nexport type BeginAuthenticationPayload =\n MutationPayloadBase<BeginAuthenticationErrorReason> & {\n lockedUntil: string | null | undefined;\n methods: readonly {\n method: AuthMethod;\n mfaEnforced?: boolean | null | undefined;\n }[];\n };\n\nexport type BeginPasskeyLoginPayload =\n MutationPayloadBase<BeginPasskeyLoginErrorReason> & {\n allowCredentials: readonly string[];\n challenge: string;\n challengeToken: string;\n rpId: string;\n };\n\ntype LoginMutationPayload = MutationPayloadBase<LoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n};\n\ntype LogoutPayload = {\n loggedOut?: boolean | null | undefined;\n};\n\ntype LogoutMutationPayload = MutationPayloadBase<LogoutErrorReason> & {\n payload?: LogoutPayload | null | undefined;\n};\n\ntype CompleteMfaMutationPayload =\n MutationPayloadBase<CompleteMfaErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype FinishPasskeyLoginMutationPayload =\n MutationPayloadBase<FinishPasskeyLoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype AcceptInvitationMutationPayload =\n MutationPayloadBase<AcceptInvitationErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\nexport type LoginResponse = { login: AuthPayload | LoginMutationPayload };\nexport type LogoutResponse = { logout: LogoutPayload | LogoutMutationPayload };\nexport type CompleteMfaResponse = {\n completeMfa: AuthPayload | CompleteMfaMutationPayload;\n};\nexport type FinishPasskeyLoginResponse = {\n finishPasskeyLogin: AuthPayload | FinishPasskeyLoginMutationPayload;\n};\nexport type AcceptInvitationResponse = {\n acceptInvitation: AuthPayload | AcceptInvitationMutationPayload;\n};\nexport type BeginAuthenticationResponse = {\n beginAuthentication: BeginAuthenticationPayload;\n};\nexport type BeginPasskeyLoginResponse = {\n beginPasskeyLogin: BeginPasskeyLoginPayload;\n};\n\nexport type LoginVariables = {\n input: LoginCredentials;\n};\n\nexport type LogoutVariables = Record<PropertyKey, never>;\n\nexport type CompleteMfaVariables = {\n input: {\n challengeToken: string;\n code: string;\n };\n};\n\nexport type BeginPasskeyLoginVariables = {\n email: string;\n};\n\nexport type FinishPasskeyLoginVariables = {\n input: {\n challenge: string;\n challengeToken: string;\n credentialId: string;\n signCount: number;\n userHandle?: string | null;\n };\n};\n\nexport type AcceptInvitationVariables = {\n input: {\n token: string;\n password: string;\n passwordConfirmation: string;\n };\n};\n\nexport type BeginAuthenticationVariables = {\n email: string;\n};\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\ntype MutationCommit<TVariables, TResponse> = (\n config: MutationCommitConfig<TVariables, TResponse>,\n) => void;\n\ntype MutationEntry<TVariables, TResponse> = {\n commit: MutationCommit<TVariables, TResponse>;\n isInFlight: boolean;\n};\n\nexport type AuthMutationHooks = {\n login: MutationEntry<LoginVariables, LoginResponse>;\n logout: MutationEntry<LogoutVariables, LogoutResponse>;\n completeMfa: MutationEntry<CompleteMfaVariables, CompleteMfaResponse>;\n beginPasskeyLogin: MutationEntry<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >;\n finishPasskeyLogin: MutationEntry<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >;\n acceptInvitation?: MutationEntry<\n AcceptInvitationVariables,\n AcceptInvitationResponse\n >;\n beginAuthentication: MutationEntry<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >;\n};\n\ninterface User {\n id: string;\n}\n\nexport type LoginStatus = 'success' | 'mfa-required' | 'error';\n\nexport interface LoginCredentials {\n email: string;\n password: string;\n}\n\nexport interface TotpCredentials {\n code: string;\n}\n\nexport interface AcceptInvitationCredentials {\n token: string;\n password: string;\n passwordConfirmation: string;\n}\n\nexport interface AuthError {\n message: string;\n code?: string;\n}\n\nexport interface UseAuthReturn {\n authMethod: AuthMethod | null;\n challengeToken: string | null;\n nextStep: LoginNextStep | null;\n mfaLevel: MfaLevel | null;\n emailHint: string | null;\n lockedUntil: string | null;\n availableMethods: AuthMethod[];\n login: (credentials: LoginCredentials) => Promise<LoginStatus>;\n loginWithPasskey: (params: { email: string }) => Promise<LoginStatus>;\n completeMfa: (credentials: TotpCredentials) => Promise<void>;\n acceptInvitation: (\n credentials: AcceptInvitationCredentials,\n ) => Promise<LoginStatus>;\n beginAuthentication: (\n email: string,\n ) => Promise<{ methods: AuthMethod[]; lockedUntil: string | null }>;\n logout: () => Promise<void>;\n reset: () => void;\n clearError: () => void;\n isLoading: boolean;\n error: AuthError | null;\n user: User | null;\n}\n\nconst initialState = {\n authMethod: null as AuthMethod | null,\n challengeToken: null as string | null,\n emailHint: null as string | null,\n mfaLevel: null as MfaLevel | null,\n nextStep: null as LoginNextStep | null,\n};\n\nexport const createUseAuth = (mutations: AuthMutationHooks) => {\n return (): UseAuthReturn => {\n const { t } = useBackofficeReactTranslation();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const [user, setUser] = useState<User | null>(null);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [availableMethods, setAvailableMethods] = useState<AuthMethod[]>([]);\n const [authState, setAuthState] = useState(initialState);\n\n const commitLoginMutation = mutations.login.commit;\n const commitLogoutMutation = mutations.logout.commit;\n const commitCompleteMfaMutation = mutations.completeMfa.commit;\n const commitBeginPasskeyLoginMutation = mutations.beginPasskeyLogin.commit;\n const commitFinishPasskeyLoginMutation =\n mutations.finishPasskeyLogin.commit;\n const commitAcceptInvitationMutation = mutations.acceptInvitation?.commit;\n const commitBeginAuthenticationMutation =\n mutations.beginAuthentication.commit;\n\n const defaultLoginErrorMessage = t('auth.loginFlow.errors.tryAgain');\n const defaultBeginAuthenticationErrorMessage = t(\n 'auth.loginFlow.errors.tryAgain',\n );\n const defaultPasskeyErrorMessage = t('auth.passkey.errors.failed');\n const defaultMfaErrorMessage = t('auth.mfa.errors.verificationFailed');\n const defaultInvitationErrorMessage = t(\n 'auth.acceptInvitation.errors.default',\n );\n const mfaInvalidChallengeMessage = t('auth.mfa.errors.invalidChallenge');\n const passkeyNotAvailableMessage = t('auth.passkey.errors.notAvailable');\n const defaultLogoutErrorMessage = t('auth.logout.errors.default');\n const passkeyCancelledMessage = t('auth.passkey.errors.cancelled');\n const passkeyNoCredentialMessage = t('auth.passkey.errors.noCredential');\n const invitationUnavailableMessage = t(\n 'auth.acceptInvitation.errors.unavailable',\n );\n\n const reset = useCallback(() => {\n setError(null);\n setUser(null);\n setLockedUntil(null);\n setAvailableMethods([]);\n setAuthState(initialState);\n }, []);\n\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n const updateAuthStateFromPayload = useCallback(\n (payload: AuthPayload): LoginStatus => {\n const authMethod = payload.authMethod ?? null;\n const challengeToken = payload.challengeToken ?? null;\n const mfaLevel = payload.mfaLevel ?? null;\n const nextStep = payload.nextStep ?? null;\n\n setAuthState((prev) => {\n return {\n ...prev,\n authMethod,\n challengeToken,\n mfaLevel,\n nextStep,\n };\n });\n\n if (payload.loggedInUser != null && nextStep == null) {\n setUser({\n id: payload.loggedInUser.id,\n });\n return 'success';\n }\n\n if (nextStep === 'TOTP' && challengeToken != null) {\n return 'mfa-required';\n }\n\n return 'error';\n },\n [],\n );\n\n const isMutationPayload = useCallback(\n (value: unknown): value is MutationPayloadBase => {\n return (\n value != null &&\n typeof value === 'object' &&\n ('status' in value || 'result' in value)\n );\n },\n [],\n );\n\n const mapLoginReason = useCallback(\n (reason: LoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CREDENTIALS':\n return t('auth.loginFlow.errors.invalidCredentials');\n case 'ACCOUNT_LOCKED':\n return t('auth.loginFlow.errors.accountLocked');\n case 'RATE_LIMITED':\n return t('auth.loginFlow.errors.rateLimited');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginAuthenticationReason = useCallback(\n (reason: BeginAuthenticationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.loginFlow.errors.invalidEmail');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginPasskeyLoginReason = useCallback(\n (reason: BeginPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.passkey.errors.invalidEmail');\n case 'PASSKEY_NOT_FOUND':\n return t('auth.passkey.errors.notFound');\n case 'PASSKEY_NOT_SUPPORTED':\n return t('auth.passkey.errors.notAvailable');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapFinishPasskeyLoginReason = useCallback(\n (reason: FinishPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.passkey.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.passkey.errors.challengeExpired');\n case 'INVALID_ASSERTION':\n return t('auth.passkey.errors.invalidAssertion');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapCompleteMfaReason = useCallback(\n (reason: CompleteMfaErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.mfa.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.mfa.errors.expired');\n case 'INVALID_CODE':\n return t('auth.mfa.errors.invalidCode');\n case 'TOO_MANY_ATTEMPTS':\n return t('auth.mfa.errors.tooManyAttempts');\n case 'INTERNAL_ERROR':\n return t('auth.mfa.errors.verificationFailed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapAcceptInvitationReason = useCallback(\n (reason: AcceptInvitationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_TOKEN':\n return t('auth.acceptInvitation.errors.invalidToken');\n case 'TOKEN_EXPIRED':\n return t('auth.acceptInvitation.errors.expired');\n case 'ALREADY_ACCEPTED':\n return t('auth.acceptInvitation.errors.alreadyAccepted');\n case 'PASSWORD_MISMATCH':\n return t('auth.acceptInvitation.errors.passwordMismatch');\n case 'PASSWORD_POLICY_VIOLATION':\n return t('auth.acceptInvitation.errors.passwordPolicyViolation');\n case 'RATE_LIMITED':\n return t('auth.acceptInvitation.errors.rateLimited');\n case 'EMAIL_MISMATCH':\n return t('auth.acceptInvitation.errors.emailMismatch');\n case 'INTERNAL_ERROR':\n return t('auth.acceptInvitation.errors.default');\n default:\n return null;\n }\n },\n [t],\n );\n\n const beginAuthentication = useCallback(\n async (\n email: string,\n ): Promise<{ methods: AuthMethod[]; lockedUntil: string | null }> => {\n return new Promise((resolve, reject) => {\n commitBeginAuthenticationMutation({\n variables: { email },\n onCompleted: (response) => {\n const rawPayload = response.beginAuthentication;\n let payload = rawPayload;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultBeginAuthenticationErrorMessage,\n mapReason: mapBeginAuthenticationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n payload = outcome.payload;\n }\n\n const methods = payload.methods.map((item) => {\n return item.method;\n });\n const locked = payload.lockedUntil ?? null;\n setAvailableMethods(methods);\n setLockedUntil(locked);\n resolve({ methods, lockedUntil: locked });\n },\n onError: () => {\n const authError: AuthError = {\n message: defaultBeginAuthenticationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginAuthenticationMutation,\n defaultBeginAuthenticationErrorMessage,\n isMutationPayload,\n mapBeginAuthenticationReason,\n ],\n );\n\n const login = useCallback(\n async (credentials: LoginCredentials): Promise<LoginStatus> => {\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: credentials.email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitLoginMutation({\n variables: {\n input: credentials,\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.login;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLoginErrorMessage,\n mapReason: mapLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitLoginMutation,\n defaultLoginErrorMessage,\n isMutationPayload,\n mapLoginReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const completeMfa = useCallback(\n async (credentials: TotpCredentials): Promise<void> => {\n const { challengeToken } = authState;\n if (challengeToken == null) {\n const authError: AuthError = {\n message: mfaInvalidChallengeMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitCompleteMfaMutation({\n variables: {\n input: {\n challengeToken,\n code: credentials.code,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.completeMfa;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultMfaErrorMessage,\n mapReason: mapCompleteMfaReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve();\n return;\n }\n\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n authState,\n commitCompleteMfaMutation,\n defaultMfaErrorMessage,\n isMutationPayload,\n mapCompleteMfaReason,\n mfaInvalidChallengeMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const loginWithPasskey = useCallback(\n async ({ email }: { email: string }): Promise<LoginStatus> => {\n if (typeof window === 'undefined') {\n const authError: AuthError = {\n message: passkeyNotAvailableMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitBeginPasskeyLoginMutation({\n variables: {\n email,\n },\n onCompleted: (response) => {\n const rawOptions = response.beginPasskeyLogin;\n let options = rawOptions;\n\n if (isMutationPayload(rawOptions)) {\n const outcome = resolveMutationOutcome(rawOptions, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapBeginPasskeyLoginReason,\n });\n if (!outcome.ok) {\n setIsLoading(false);\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n options = outcome.payload;\n }\n\n const continuePasskeyLogin = async (): Promise<void> => {\n try {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n allowCredentials: options.allowCredentials.map(\n (credentialId) => {\n return {\n id: base64UrlToBuffer(credentialId),\n type: 'public-key' as const,\n };\n },\n ),\n challenge: base64UrlToBuffer(options.challenge),\n rpId: options.rpId,\n userVerification: 'preferred',\n },\n })) as PublicKeyCredential | null;\n\n if (assertion == null) {\n throw new Error('PASSKEY_NO_CREDENTIAL');\n }\n\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const signCount = parseSignCount(\n assertionResponse.authenticatorData,\n );\n\n commitFinishPasskeyLoginMutation({\n variables: {\n input: {\n challenge: options.challenge,\n challengeToken: options.challengeToken,\n credentialId: assertion.id,\n signCount,\n userHandle:\n assertionResponse.userHandle != null\n ? bufferToBase64Url(assertionResponse.userHandle)\n : null,\n },\n },\n onCompleted: (finishResponse) => {\n setIsLoading(false);\n const rawPayload = finishResponse.finishPasskeyLogin;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapFinishPasskeyLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n } catch (credentialError) {\n setIsLoading(false);\n let message = defaultPasskeyErrorMessage;\n if (\n credentialError instanceof Error &&\n credentialError.message === 'PASSKEY_NO_CREDENTIAL'\n ) {\n message = passkeyNoCredentialMessage;\n } else if (\n typeof DOMException !== 'undefined' &&\n credentialError instanceof DOMException\n ) {\n if (\n credentialError.name === 'AbortError' ||\n credentialError.name === 'NotAllowedError'\n ) {\n message = passkeyCancelledMessage;\n } else if (\n credentialError.name === 'InvalidStateError' ||\n credentialError.name === 'NotSupportedError' ||\n credentialError.name === 'SecurityError'\n ) {\n message = passkeyNotAvailableMessage;\n }\n }\n const authError: AuthError = {\n message,\n };\n setError(authError);\n reject(authError);\n }\n };\n\n continuePasskeyLogin().catch(() => {\n return undefined;\n });\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginPasskeyLoginMutation,\n commitFinishPasskeyLoginMutation,\n defaultPasskeyErrorMessage,\n isMutationPayload,\n mapBeginPasskeyLoginReason,\n mapFinishPasskeyLoginReason,\n passkeyCancelledMessage,\n passkeyNoCredentialMessage,\n passkeyNotAvailableMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const acceptInvitation = useCallback(\n async (\n credentials: AcceptInvitationCredentials,\n ): Promise<LoginStatus> => {\n if (commitAcceptInvitationMutation == null) {\n const authError: AuthError = {\n message: invitationUnavailableMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitAcceptInvitationMutation({\n variables: {\n input: {\n token: credentials.token,\n password: credentials.password,\n passwordConfirmation: credentials.passwordConfirmation,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.acceptInvitation;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultInvitationErrorMessage,\n mapReason: mapAcceptInvitationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitAcceptInvitationMutation,\n defaultInvitationErrorMessage,\n invitationUnavailableMessage,\n isMutationPayload,\n mapAcceptInvitationReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const logout = useCallback(async (): Promise<void> => {\n setIsLoading(true);\n\n return new Promise((resolve, reject) => {\n commitLogoutMutation({\n variables: {},\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.logout;\n let loggedOutValue: boolean | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLogoutErrorMessage,\n });\n if (!outcome.ok) {\n const authError: AuthError = { message: outcome.message };\n setError(authError);\n reject(authError);\n return;\n }\n\n const loggedOutResult = requireField(\n rawPayload.payload?.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n } else {\n const loggedOutResult = requireField(\n rawPayload.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n }\n\n if (!loggedOutValue) {\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n setUser(null);\n setAuthState(initialState);\n resetRelayStore();\n\n resolve();\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n resetRelayStore();\n\n reject(authError);\n },\n });\n });\n }, [commitLogoutMutation, defaultLogoutErrorMessage, isMutationPayload]);\n\n const combinedIsLoading =\n isLoading ||\n mutations.login.isInFlight ||\n mutations.logout.isInFlight ||\n mutations.completeMfa.isInFlight ||\n mutations.beginPasskeyLogin.isInFlight ||\n mutations.finishPasskeyLogin.isInFlight ||\n (mutations.acceptInvitation?.isInFlight ?? false) ||\n mutations.beginAuthentication.isInFlight;\n\n return {\n authMethod: authState.authMethod,\n challengeToken: authState.challengeToken,\n nextStep: authState.nextStep,\n mfaLevel: authState.mfaLevel,\n emailHint: authState.emailHint,\n login,\n loginWithPasskey,\n completeMfa,\n acceptInvitation,\n beginAuthentication,\n logout,\n reset,\n clearError,\n isLoading: combinedIsLoading,\n error,\n user,\n lockedUntil,\n availableMethods,\n };\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useAuth.js","names":[],"sources":["../../../src/hooks/useAuth.ts"],"sourcesContent":["/* eslint-disable no-ternary */\nimport { useCallback, useState } from 'react';\n\nimport {\n type MutationPayloadBase,\n requireField,\n resolveMutationOutcome,\n} from '../relay/mutationResult.js';\nimport { useBackofficeReactTranslation } from '../i18n/useBackofficeReactTranslation.js';\n\nimport { resetRelayStore } from '../relay/environment.js';\nimport type { PayloadError } from 'relay-runtime';\n\nimport type {\n AuthMethod,\n LoginNextStep,\n MfaLevel,\n} from '../modules/sharedSchemaTypes.js';\nimport {\n base64UrlToBuffer,\n bufferToBase64Url,\n parseSignCount,\n} from '../modules/webauthn.js';\n\nexport type AuthPayload = {\n authMethod: AuthMethod | null | undefined;\n challengeToken: string | null | undefined;\n loggedInUser: { id: string } | null | undefined;\n mfaLevel: MfaLevel | null | undefined;\n nextStep: LoginNextStep | null | undefined;\n};\n\ntype LoginErrorReason =\n | 'INVALID_CREDENTIALS'\n | 'ACCOUNT_LOCKED'\n | 'RATE_LIMITED'\n | 'INTERNAL_ERROR';\n\ntype LogoutErrorReason =\n | 'UNAUTHENTICATED'\n | 'SESSION_NOT_FOUND'\n | 'INTERNAL_ERROR';\n\ntype BeginAuthenticationErrorReason = 'INVALID_EMAIL' | 'INTERNAL_ERROR';\n\ntype BeginPasskeyLoginErrorReason =\n | 'INVALID_EMAIL'\n | 'PASSKEY_NOT_FOUND'\n | 'PASSKEY_NOT_SUPPORTED'\n | 'INTERNAL_ERROR';\n\ntype FinishPasskeyLoginErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_ASSERTION'\n | 'INTERNAL_ERROR';\n\ntype CompleteMfaErrorReason =\n | 'INVALID_CHALLENGE_TOKEN'\n | 'CHALLENGE_EXPIRED'\n | 'INVALID_CODE'\n | 'TOO_MANY_ATTEMPTS'\n | 'INTERNAL_ERROR';\n\ntype AcceptInvitationErrorReason =\n | 'INVALID_TOKEN'\n | 'TOKEN_EXPIRED'\n | 'ALREADY_ACCEPTED'\n | 'PASSWORD_MISMATCH'\n | 'PASSWORD_POLICY_VIOLATION'\n | 'RATE_LIMITED'\n | 'EMAIL_MISMATCH'\n | 'INTERNAL_ERROR';\n\nexport type BeginAuthenticationPayload =\n MutationPayloadBase<BeginAuthenticationErrorReason> & {\n lockedUntil: string | null | undefined;\n methods: readonly {\n method: AuthMethod;\n mfaEnforced?: boolean | null | undefined;\n }[];\n };\n\nexport type BeginPasskeyLoginPayload =\n MutationPayloadBase<BeginPasskeyLoginErrorReason> & {\n allowCredentials: readonly string[];\n challenge: string;\n challengeToken: string;\n rpId: string;\n };\n\ntype LoginMutationPayload = MutationPayloadBase<LoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n};\n\ntype LogoutPayload = {\n loggedOut?: boolean | null | undefined;\n};\n\ntype LogoutMutationPayload = MutationPayloadBase<LogoutErrorReason> & {\n payload?: LogoutPayload | null | undefined;\n};\n\ntype CompleteMfaMutationPayload =\n MutationPayloadBase<CompleteMfaErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype FinishPasskeyLoginMutationPayload =\n MutationPayloadBase<FinishPasskeyLoginErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\ntype AcceptInvitationMutationPayload =\n MutationPayloadBase<AcceptInvitationErrorReason> & {\n payload?: AuthPayload | null | undefined;\n };\n\nexport type LoginResponse = { login: AuthPayload | LoginMutationPayload };\nexport type LogoutResponse = { logout: LogoutPayload | LogoutMutationPayload };\nexport type CompleteMfaResponse = {\n completeMfa: AuthPayload | CompleteMfaMutationPayload;\n};\nexport type FinishPasskeyLoginResponse = {\n finishPasskeyLogin: AuthPayload | FinishPasskeyLoginMutationPayload;\n};\nexport type AcceptInvitationResponse = {\n acceptInvitation: AuthPayload | AcceptInvitationMutationPayload;\n};\nexport type BeginAuthenticationResponse = {\n beginAuthentication: BeginAuthenticationPayload;\n};\nexport type BeginPasskeyLoginResponse = {\n beginPasskeyLogin: BeginPasskeyLoginPayload;\n};\n\nexport type LoginVariables = {\n input: LoginCredentials;\n};\n\nexport type LogoutVariables = Record<PropertyKey, never>;\n\nexport type CompleteMfaVariables = {\n input: {\n challengeToken: string;\n code: string;\n };\n};\n\nexport type BeginPasskeyLoginVariables = {\n email: string;\n};\n\nexport type FinishPasskeyLoginVariables = {\n input: {\n challenge: string;\n challengeToken: string;\n credentialId: string;\n signCount: number;\n userHandle?: string | null;\n };\n};\n\nexport type AcceptInvitationVariables = {\n input: {\n token: string;\n password: string;\n passwordConfirmation: string;\n };\n};\n\nexport type BeginAuthenticationVariables = {\n email: string;\n};\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\ntype MutationCommit<TVariables, TResponse> = (\n config: MutationCommitConfig<TVariables, TResponse>,\n) => void;\n\ntype MutationEntry<TVariables, TResponse> = {\n commit: MutationCommit<TVariables, TResponse>;\n isInFlight: boolean;\n};\n\nexport type AuthMutationHooks = {\n login: MutationEntry<LoginVariables, LoginResponse>;\n logout: MutationEntry<LogoutVariables, LogoutResponse>;\n completeMfa: MutationEntry<CompleteMfaVariables, CompleteMfaResponse>;\n beginPasskeyLogin: MutationEntry<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >;\n finishPasskeyLogin: MutationEntry<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >;\n acceptInvitation?: MutationEntry<\n AcceptInvitationVariables,\n AcceptInvitationResponse\n >;\n beginAuthentication: MutationEntry<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >;\n};\n\ninterface User {\n id: string;\n}\n\nexport type LoginStatus = 'success' | 'mfa-required' | 'error';\n\nexport interface LoginCredentials {\n email: string;\n password: string;\n}\n\nexport interface TotpCredentials {\n code: string;\n}\n\nexport interface AcceptInvitationCredentials {\n token: string;\n password: string;\n passwordConfirmation: string;\n}\n\nexport interface AuthError {\n message: string;\n code?: string;\n}\n\nexport interface UseAuthReturn {\n authMethod: AuthMethod | null;\n challengeToken: string | null;\n nextStep: LoginNextStep | null;\n mfaLevel: MfaLevel | null;\n emailHint: string | null;\n lockedUntil: string | null;\n availableMethods: AuthMethod[];\n login: (credentials: LoginCredentials) => Promise<LoginStatus>;\n loginWithPasskey: (params: { email: string }) => Promise<LoginStatus>;\n completeMfa: (credentials: TotpCredentials) => Promise<void>;\n acceptInvitation: (\n credentials: AcceptInvitationCredentials,\n ) => Promise<LoginStatus>;\n beginAuthentication: (\n email: string,\n ) => Promise<{ methods: AuthMethod[]; lockedUntil: string | null }>;\n logout: () => Promise<void>;\n reset: () => void;\n clearError: () => void;\n isLoading: boolean;\n error: AuthError | null;\n user: User | null;\n}\n\nconst initialState = {\n authMethod: null as AuthMethod | null,\n challengeToken: null as string | null,\n emailHint: null as string | null,\n mfaLevel: null as MfaLevel | null,\n nextStep: null as LoginNextStep | null,\n};\n\nexport const createUseAuth = (mutations: AuthMutationHooks) => {\n return (): UseAuthReturn => {\n const { t } = useBackofficeReactTranslation();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const [user, setUser] = useState<User | null>(null);\n const [lockedUntil, setLockedUntil] = useState<string | null>(null);\n const [availableMethods, setAvailableMethods] = useState<AuthMethod[]>([]);\n const [authState, setAuthState] = useState(initialState);\n\n const commitLoginMutation = mutations.login.commit;\n const commitLogoutMutation = mutations.logout.commit;\n const commitCompleteMfaMutation = mutations.completeMfa.commit;\n const commitBeginPasskeyLoginMutation = mutations.beginPasskeyLogin.commit;\n const commitFinishPasskeyLoginMutation =\n mutations.finishPasskeyLogin.commit;\n const commitAcceptInvitationMutation = mutations.acceptInvitation?.commit;\n const commitBeginAuthenticationMutation =\n mutations.beginAuthentication.commit;\n\n const defaultLoginErrorMessage = t('auth.loginFlow.errors.tryAgain');\n const defaultBeginAuthenticationErrorMessage = t(\n 'auth.loginFlow.errors.tryAgain',\n );\n const defaultPasskeyErrorMessage = t('auth.passkey.errors.failed');\n const defaultMfaErrorMessage = t('auth.mfa.errors.verificationFailed');\n const defaultInvitationErrorMessage = t(\n 'auth.acceptInvitation.errors.default',\n );\n const mfaInvalidChallengeMessage = t('auth.mfa.errors.invalidChallenge');\n const passkeyNotAvailableMessage = t('auth.passkey.errors.notAvailable');\n const defaultLogoutErrorMessage = t('auth.logout.errors.default');\n const passkeyCancelledMessage = t('auth.passkey.errors.cancelled');\n const passkeyNoCredentialMessage = t('auth.passkey.errors.noCredential');\n const invitationUnavailableMessage = t(\n 'auth.acceptInvitation.errors.unavailable',\n );\n\n const reset = useCallback(() => {\n setError(null);\n setUser(null);\n setLockedUntil(null);\n setAvailableMethods([]);\n setAuthState(initialState);\n }, []);\n\n const clearError = useCallback(() => {\n setError(null);\n }, []);\n\n const updateAuthStateFromPayload = useCallback(\n (payload: AuthPayload): LoginStatus => {\n const authMethod = payload.authMethod ?? null;\n const challengeToken = payload.challengeToken ?? null;\n const mfaLevel = payload.mfaLevel ?? null;\n const nextStep = payload.nextStep ?? null;\n\n setAuthState((prev) => {\n return {\n ...prev,\n authMethod,\n challengeToken,\n mfaLevel,\n nextStep,\n };\n });\n\n if (payload.loggedInUser != null && nextStep == null) {\n setUser({\n id: payload.loggedInUser.id,\n });\n return 'success';\n }\n\n if (nextStep === 'TOTP' && challengeToken != null) {\n return 'mfa-required';\n }\n\n return 'error';\n },\n [],\n );\n\n const isMutationPayload = useCallback(\n (value: unknown): value is MutationPayloadBase => {\n return (\n value != null &&\n typeof value === 'object' &&\n ('status' in value || 'result' in value)\n );\n },\n [],\n );\n\n const mapLoginReason = useCallback(\n (reason: LoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CREDENTIALS':\n return t('auth.loginFlow.errors.invalidCredentials');\n case 'ACCOUNT_LOCKED':\n return t('auth.loginFlow.errors.accountLocked');\n case 'RATE_LIMITED':\n return t('auth.loginFlow.errors.rateLimited');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginAuthenticationReason = useCallback(\n (reason: BeginAuthenticationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.loginFlow.errors.invalidEmail');\n case 'INTERNAL_ERROR':\n return t('auth.loginFlow.errors.tryAgain');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapBeginPasskeyLoginReason = useCallback(\n (reason: BeginPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_EMAIL':\n return t('auth.passkey.errors.invalidEmail');\n case 'PASSKEY_NOT_FOUND':\n return t('auth.passkey.errors.notFound');\n case 'PASSKEY_NOT_SUPPORTED':\n return t('auth.passkey.errors.notAvailable');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapFinishPasskeyLoginReason = useCallback(\n (reason: FinishPasskeyLoginErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.passkey.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.passkey.errors.challengeExpired');\n case 'INVALID_ASSERTION':\n return t('auth.passkey.errors.invalidAssertion');\n case 'INTERNAL_ERROR':\n return t('auth.passkey.errors.failed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapCompleteMfaReason = useCallback(\n (reason: CompleteMfaErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_CHALLENGE_TOKEN':\n return t('auth.mfa.errors.invalidChallenge');\n case 'CHALLENGE_EXPIRED':\n return t('auth.mfa.errors.expired');\n case 'INVALID_CODE':\n return t('auth.mfa.errors.invalidCode');\n case 'TOO_MANY_ATTEMPTS':\n return t('auth.mfa.errors.tooManyAttempts');\n case 'INTERNAL_ERROR':\n return t('auth.mfa.errors.verificationFailed');\n default:\n return null;\n }\n },\n [t],\n );\n\n const mapAcceptInvitationReason = useCallback(\n (reason: AcceptInvitationErrorReason): string | null => {\n switch (reason) {\n case 'INVALID_TOKEN':\n return t('auth.acceptInvitation.errors.invalidToken');\n case 'TOKEN_EXPIRED':\n return t('auth.acceptInvitation.errors.expired');\n case 'ALREADY_ACCEPTED':\n return t('auth.acceptInvitation.errors.alreadyAccepted');\n case 'PASSWORD_MISMATCH':\n return t('auth.acceptInvitation.errors.passwordMismatch');\n case 'PASSWORD_POLICY_VIOLATION':\n return t('auth.acceptInvitation.errors.passwordPolicyViolation');\n case 'RATE_LIMITED':\n return t('auth.acceptInvitation.errors.rateLimited');\n case 'EMAIL_MISMATCH':\n return t('auth.acceptInvitation.errors.emailMismatch');\n case 'INTERNAL_ERROR':\n return t('auth.acceptInvitation.errors.default');\n default:\n return null;\n }\n },\n [t],\n );\n\n const beginAuthentication = useCallback(\n async (\n email: string,\n ): Promise<{ methods: AuthMethod[]; lockedUntil: string | null }> => {\n return new Promise((resolve, reject) => {\n commitBeginAuthenticationMutation({\n variables: { email },\n onCompleted: (response) => {\n const rawPayload = response.beginAuthentication;\n let payload = rawPayload;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultBeginAuthenticationErrorMessage,\n mapReason: mapBeginAuthenticationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n payload = outcome.payload;\n }\n\n const methods = payload.methods.map((item) => {\n return item.method;\n });\n const locked = payload.lockedUntil ?? null;\n setAvailableMethods(methods);\n setLockedUntil(locked);\n resolve({ methods, lockedUntil: locked });\n },\n onError: () => {\n const authError: AuthError = {\n message: defaultBeginAuthenticationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginAuthenticationMutation,\n defaultBeginAuthenticationErrorMessage,\n isMutationPayload,\n mapBeginAuthenticationReason,\n ],\n );\n\n const login = useCallback(\n async (credentials: LoginCredentials): Promise<LoginStatus> => {\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: credentials.email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitLoginMutation({\n variables: {\n input: credentials,\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.login;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLoginErrorMessage,\n mapReason: mapLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLoginErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitLoginMutation,\n defaultLoginErrorMessage,\n isMutationPayload,\n mapLoginReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const completeMfa = useCallback(\n async (credentials: TotpCredentials): Promise<void> => {\n const { challengeToken } = authState;\n if (challengeToken == null) {\n const authError: AuthError = {\n message: mfaInvalidChallengeMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitCompleteMfaMutation({\n variables: {\n input: {\n challengeToken,\n code: credentials.code,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.completeMfa;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultMfaErrorMessage,\n mapReason: mapCompleteMfaReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve();\n return;\n }\n\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultMfaErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n authState,\n commitCompleteMfaMutation,\n defaultMfaErrorMessage,\n isMutationPayload,\n mapCompleteMfaReason,\n mfaInvalidChallengeMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const loginWithPasskey = useCallback(\n async ({ email }: { email: string }): Promise<LoginStatus> => {\n if (typeof window === 'undefined') {\n const authError: AuthError = {\n message: passkeyNotAvailableMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n setAuthState((prev) => {\n return {\n ...prev,\n emailHint: email,\n };\n });\n\n return new Promise((resolve, reject) => {\n commitBeginPasskeyLoginMutation({\n variables: {\n email,\n },\n onCompleted: (response) => {\n const rawOptions = response.beginPasskeyLogin;\n let options = rawOptions;\n\n if (isMutationPayload(rawOptions)) {\n const outcome = resolveMutationOutcome(rawOptions, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapBeginPasskeyLoginReason,\n });\n if (!outcome.ok) {\n setIsLoading(false);\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n options = outcome.payload;\n }\n\n const continuePasskeyLogin = async (): Promise<void> => {\n try {\n const assertion = (await navigator.credentials.get({\n publicKey: {\n allowCredentials: options.allowCredentials.map(\n (credentialId) => {\n return {\n id: base64UrlToBuffer(credentialId),\n type: 'public-key' as const,\n };\n },\n ),\n challenge: base64UrlToBuffer(options.challenge),\n rpId: options.rpId,\n userVerification: 'preferred',\n },\n })) as PublicKeyCredential | null;\n\n if (assertion == null) {\n throw new Error('PASSKEY_NO_CREDENTIAL');\n }\n\n const assertionResponse =\n assertion.response as AuthenticatorAssertionResponse;\n const signCount = parseSignCount(\n assertionResponse.authenticatorData,\n );\n\n commitFinishPasskeyLoginMutation({\n variables: {\n input: {\n challenge: options.challenge,\n challengeToken: options.challengeToken,\n credentialId: assertion.id,\n signCount,\n userHandle:\n assertionResponse.userHandle != null\n ? bufferToBase64Url(assertionResponse.userHandle)\n : null,\n },\n },\n onCompleted: (finishResponse) => {\n setIsLoading(false);\n const rawPayload = finishResponse.finishPasskeyLogin;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultPasskeyErrorMessage,\n mapReason: mapFinishPasskeyLoginReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n } catch (credentialError) {\n setIsLoading(false);\n let message = defaultPasskeyErrorMessage;\n if (\n credentialError instanceof Error &&\n credentialError.message === 'PASSKEY_NO_CREDENTIAL'\n ) {\n message = passkeyNoCredentialMessage;\n } else if (\n typeof DOMException !== 'undefined' &&\n credentialError instanceof DOMException\n ) {\n if (\n credentialError.name === 'AbortError' ||\n credentialError.name === 'NotAllowedError'\n ) {\n message = passkeyCancelledMessage;\n } else if (\n credentialError.name === 'InvalidStateError' ||\n credentialError.name === 'NotSupportedError' ||\n credentialError.name === 'SecurityError'\n ) {\n message = passkeyNotAvailableMessage;\n }\n }\n const authError: AuthError = {\n message,\n };\n setError(authError);\n reject(authError);\n }\n };\n\n continuePasskeyLogin().catch(() => {\n return undefined;\n });\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultPasskeyErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitBeginPasskeyLoginMutation,\n commitFinishPasskeyLoginMutation,\n defaultPasskeyErrorMessage,\n isMutationPayload,\n mapBeginPasskeyLoginReason,\n mapFinishPasskeyLoginReason,\n passkeyCancelledMessage,\n passkeyNoCredentialMessage,\n passkeyNotAvailableMessage,\n updateAuthStateFromPayload,\n ],\n );\n\n const acceptInvitation = useCallback(\n async (\n credentials: AcceptInvitationCredentials,\n ): Promise<LoginStatus> => {\n if (commitAcceptInvitationMutation == null) {\n const authError: AuthError = {\n message: invitationUnavailableMessage,\n };\n setError(authError);\n return Promise.reject(authError);\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise((resolve, reject) => {\n commitAcceptInvitationMutation({\n variables: {\n input: {\n token: credentials.token,\n password: credentials.password,\n passwordConfirmation: credentials.passwordConfirmation,\n },\n },\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.acceptInvitation;\n let authPayload: AuthPayload | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultInvitationErrorMessage,\n mapReason: mapAcceptInvitationReason,\n });\n if (!outcome.ok) {\n const authError: AuthError = {\n message: outcome.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n authPayload = rawPayload.payload ?? null;\n } else {\n authPayload = rawPayload;\n }\n\n if (authPayload == null) {\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n const status = updateAuthStateFromPayload(authPayload);\n if (status === 'success' || status === 'mfa-required') {\n resolve(status);\n return;\n }\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultInvitationErrorMessage,\n };\n setError(authError);\n reject(authError);\n },\n });\n });\n },\n [\n commitAcceptInvitationMutation,\n defaultInvitationErrorMessage,\n invitationUnavailableMessage,\n isMutationPayload,\n mapAcceptInvitationReason,\n updateAuthStateFromPayload,\n ],\n );\n\n const logout = useCallback(async (): Promise<void> => {\n setIsLoading(true);\n\n return new Promise((resolve, reject) => {\n commitLogoutMutation({\n variables: {},\n onCompleted: (response) => {\n setIsLoading(false);\n const rawPayload = response.logout;\n let loggedOutValue: boolean | null = null;\n\n if (isMutationPayload(rawPayload)) {\n const outcome = resolveMutationOutcome(rawPayload, {\n defaultErrorMessage: defaultLogoutErrorMessage,\n });\n if (!outcome.ok) {\n const authError: AuthError = { message: outcome.message };\n setError(authError);\n reject(authError);\n return;\n }\n\n const loggedOutResult = requireField(\n rawPayload.payload?.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n } else {\n const loggedOutResult = requireField(\n rawPayload.loggedOut ?? null,\n defaultLogoutErrorMessage,\n );\n if (!loggedOutResult.ok) {\n const authError: AuthError = {\n message: loggedOutResult.message,\n };\n setError(authError);\n reject(authError);\n return;\n }\n loggedOutValue = loggedOutResult.value;\n }\n\n if (!loggedOutValue) {\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n reject(authError);\n return;\n }\n\n localStorage.removeItem('auth_token');\n localStorage.removeItem('remember_me');\n setUser(null);\n setAuthState(initialState);\n resetRelayStore();\n\n resolve();\n },\n onError: () => {\n setIsLoading(false);\n const authError: AuthError = {\n message: defaultLogoutErrorMessage,\n };\n setError(authError);\n resetRelayStore();\n\n reject(authError);\n },\n });\n });\n }, [commitLogoutMutation, defaultLogoutErrorMessage, isMutationPayload]);\n\n const combinedIsLoading =\n isLoading ||\n mutations.login.isInFlight ||\n mutations.logout.isInFlight ||\n mutations.completeMfa.isInFlight ||\n mutations.beginPasskeyLogin.isInFlight ||\n mutations.finishPasskeyLogin.isInFlight ||\n (mutations.acceptInvitation?.isInFlight ?? false) ||\n mutations.beginAuthentication.isInFlight;\n\n return {\n authMethod: authState.authMethod,\n challengeToken: authState.challengeToken,\n nextStep: authState.nextStep,\n mfaLevel: authState.mfaLevel,\n emailHint: authState.emailHint,\n login,\n loginWithPasskey,\n completeMfa,\n acceptInvitation,\n beginAuthentication,\n logout,\n reset,\n clearError,\n isLoading: combinedIsLoading,\n error,\n user,\n lockedUntil,\n availableMethods,\n };\n };\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeAuth.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLTaggedNode, PayloadError } from 'relay-runtime';\n\nimport {\n createUseAuth,\n type UseAuthReturn,\n type AcceptInvitationResponse,\n type AcceptInvitationVariables,\n type BeginAuthenticationResponse,\n type BeginAuthenticationVariables,\n type BeginPasskeyLoginResponse,\n type BeginPasskeyLoginVariables,\n type CompleteMfaResponse,\n type CompleteMfaVariables,\n type FinishPasskeyLoginResponse,\n type FinishPasskeyLoginVariables,\n type LoginResponse,\n type LoginVariables,\n type LogoutResponse,\n type LogoutVariables,\n} from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { BackofficeLazyValue } from '../provider/lazyValue.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\n\nconst { commitMutation } = ReactRelay;\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\nconst toMutationLoadError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Unable to load auth mutation.');\n};\n\nconst useDeferredMutation = <TVariables extends object, TResponse>(\n loadMutation: () => Promise<GraphQLTaggedNode | null>,\n) => {\n const relayEnvironment = useRelayEnvironment();\n const [inFlightCount, setInFlightCount] = useState(0);\n\n const commit = useCallback(\n (config: MutationCommitConfig<TVariables, TResponse>) => {\n setInFlightCount((count) => {\n return count + 1;\n });\n\n const finish = () => {\n setInFlightCount((count) => {\n return Math.max(0, count - 1);\n });\n };\n\n loadMutation()\n .then((mutation) => {\n if (mutation == null) {\n throw new Error('Missing auth mutation config.');\n }\n\n commitMutation(relayEnvironment, {\n mutation,\n variables: config.variables,\n onCompleted: (response, errors) => {\n finish();\n config.onCompleted?.(response as TResponse, errors ?? null);\n },\n onError: (error) => {\n finish();\n config.onError?.(error);\n },\n });\n })\n .catch((error: unknown) => {\n finish();\n config.onError?.(toMutationLoadError(error));\n });\n },\n [loadMutation, relayEnvironment],\n );\n\n return {\n commit,\n isInFlight: inFlightCount > 0,\n };\n};\n\nconst loadOptionalMutation = async <TConfig>(\n eagerMutation: GraphQLTaggedNode | null | undefined,\n lazyConfig: BackofficeLazyValue<TConfig> | null | undefined,\n selectMutation: (config: TConfig) => GraphQLTaggedNode,\n): Promise<GraphQLTaggedNode | null> => {\n if (eagerMutation != null) {\n return eagerMutation;\n }\n if (lazyConfig == null) {\n return null;\n }\n const loadedConfig = await lazyConfig.load();\n return selectMutation(loadedConfig);\n};\n\n/**\n * Provides auth actions/state backed by Relay mutations from BackofficeProvider.\n */\nexport function useBackofficeAuth(): UseAuthReturn {\n const { auth: authConfig } = useBackofficeConfig();\n const { commit: commitLogin, isInFlight: isLoginInFlight } =\n useDeferredMutation<LoginVariables, LoginResponse>(\n useCallback(async () => {\n const loginConfig = authConfig.login.get();\n return loadOptionalMutation(\n loginConfig?.loginMutation,\n authConfig.login,\n (config) => {\n return config.loginMutation;\n },\n );\n }, [authConfig.login]),\n );\n const { commit: commitLogout, isInFlight: isLogoutInFlight } =\n useDeferredMutation<LogoutVariables, LogoutResponse>(\n useCallback(async () => {\n const logoutConfig = await authConfig.logout.load();\n return logoutConfig.logoutMutation;\n }, [authConfig.logout]),\n );\n const { commit: commitCompleteMfa, isInFlight: isCompleteMfaInFlight } =\n useDeferredMutation<CompleteMfaVariables, CompleteMfaResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.completeMfaMutation,\n authConfig.completeMfa,\n (config) => {\n return config.completeMfaMutation;\n },\n );\n }, [authConfig.completeMfa, authConfig.login]),\n );\n const {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n } = useDeferredMutation<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.beginPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n } = useDeferredMutation<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.finishPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.finishPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n } = useDeferredMutation<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginAuthenticationMutation,\n authConfig.authentication,\n (config) => {\n return config.beginAuthenticationMutation;\n },\n );\n }, [authConfig.authentication, authConfig.login]),\n );\n const {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n } = useDeferredMutation<AcceptInvitationVariables, AcceptInvitationResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.acceptInvitationMutation,\n authConfig.acceptInvitation,\n (config) => {\n return config.acceptInvitationMutation;\n },\n );\n }, [authConfig.acceptInvitation, authConfig.login]),\n );\n const hasAcceptInvitationMutation =\n authConfig.login.get()?.acceptInvitationMutation != null ||\n authConfig.acceptInvitation != null;\n\n const useAuthWithMutations = useMemo(() => {\n let acceptInvitation:\n | {\n commit: typeof commitAcceptInvitation;\n isInFlight: boolean;\n }\n | undefined;\n if (hasAcceptInvitationMutation) {\n acceptInvitation = {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n };\n }\n return createUseAuth({\n login: { commit: commitLogin, isInFlight: isLoginInFlight },\n logout: { commit: commitLogout, isInFlight: isLogoutInFlight },\n completeMfa: {\n commit: commitCompleteMfa,\n isInFlight: isCompleteMfaInFlight,\n },\n beginPasskeyLogin: {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n },\n finishPasskeyLogin: {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n },\n beginAuthentication: {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n },\n acceptInvitation,\n });\n }, [\n commitAcceptInvitation,\n commitBeginAuthentication,\n commitBeginPasskeyLogin,\n commitCompleteMfa,\n commitFinishPasskeyLogin,\n commitLogin,\n commitLogout,\n hasAcceptInvitationMutation,\n isAcceptInvitationInFlight,\n isBeginAuthenticationInFlight,\n isBeginPasskeyLoginInFlight,\n isCompleteMfaInFlight,\n isFinishPasskeyLoginInFlight,\n isLoginInFlight,\n isLogoutInFlight,\n ]);\n\n return useAuthWithMutations();\n}\n"],"mappings":";;;;;;AA0BA,IAAM,EAAE,gBAAA,MAAmB,GAWrB,KAAuB,MACvB,aAAiB,QACZ,IAEF,gBAAI,MAAM,gCAAgC,EAG7C,KACJ,MACG;CACH,IAAM,IAAmB,GAAqB,EACxC,CAAC,GAAe,KAAoB,EAAS,EAAE;CAyCrD,OAAO;EACL,QAxCa,GACZ,MAAwD;GACvD,GAAkB,MACT,IAAQ,EACf;GAEF,IAAM,UAAe;IACnB,GAAkB,MACT,KAAK,IAAI,GAAG,IAAQ,EAAE,CAC7B;;GAGJ,GAAc,CACX,MAAM,MAAa;IAClB,IAAI,KAAY,MACd,MAAU,MAAM,gCAAgC;IAGlD,EAAe,GAAkB;KAC/B;KACA,WAAW,EAAO;KAClB,cAAc,GAAU,MAAW;MAEjC,AADA,GAAQ,EACR,EAAO,cAAc,GAAuB,KAAU,KAAK;;KAE7D,UAAU,MAAU;MAElB,AADA,GAAQ,EACR,EAAO,UAAU,EAAM;;KAE1B,CAAC;KACF,CACD,OAAO,MAAmB;IAEzB,AADA,GAAQ,EACR,EAAO,UAAU,EAAoB,EAAM,CAAC;KAC5C;KAEN,CAAC,GAAc,EAAiB,CAIhC;EACA,YAAY,IAAgB;EAC7B;GAGG,IAAuB,OAC3B,GACA,GACA,MAEI,MAGA,KAAc,OACT,OAGF,EAAe,MADK,EAAW,MAAM,CACT;AAMrC,SAAgB,IAAmC;CACjD,IAAM,EAAE,MAAM,MAAe,GAAqB,EAC5C,EAAE,QAAQ,GAAa,YAAY,MACvC,EACE,EAAY,YAEH,EADa,EAAW,MAAM,KAEnC,EAAa,eACb,EAAW,QACV,MACQ,EAAO,cAEjB,EACA,CAAC,EAAW,MAAM,CAAC,CACvB,EACG,EAAE,QAAQ,GAAc,YAAY,MACxC,EACE,EAAY,aAEH,MADoB,EAAW,OAAO,MAAM,EAC/B,gBACnB,CAAC,EAAW,OAAO,CAAC,CACxB,EACG,EAAE,QAAQ,GAAmB,YAAY,MAC7C,EACE,EAAY,YACH,EACL,EAAW,MAAM,KAAK,EAAE,qBACxB,EAAW,cACV,MACQ,EAAO,oBAEjB,EACA,CAAC,EAAW,aAAa,EAAW,MAAM,CAAC,CAC/C,EACG,EACJ,QAAQ,GACR,YAAY,MACV,EAIF,EAAY,YACH,EACL,EAAW,MAAM,KAAK,EAAE,2BACxB,EAAW,eACV,MACQ,EAAO,0BAEjB,EACA,CAAC,EAAW,OAAO,EAAW,aAAa,CAAC,CAChD,EACK,EACJ,QAAQ,GACR,YAAY,MACV,EAIF,EAAY,YACH,EACL,EAAW,MAAM,KAAK,EAAE,4BACxB,EAAW,eACV,MACQ,EAAO,2BAEjB,EACA,CAAC,EAAW,OAAO,EAAW,aAAa,CAAC,CAChD,EACK,EACJ,QAAQ,GACR,YAAY,MACV,EAIF,EAAY,YACH,EACL,EAAW,MAAM,KAAK,EAAE,6BACxB,EAAW,iBACV,MACQ,EAAO,4BAEjB,EACA,CAAC,EAAW,gBAAgB,EAAW,MAAM,CAAC,CAClD,EACK,EACJ,QAAQ,GACR,YAAY,MACV,EACF,EAAY,YACH,EACL,EAAW,MAAM,KAAK,EAAE,0BACxB,EAAW,mBACV,MACQ,EAAO,yBAEjB,EACA,CAAC,EAAW,kBAAkB,EAAW,MAAM,CAAC,CACpD,EACK,IACJ,EAAW,MAAM,KAAK,EAAE,4BAA4B,QACpD,EAAW,oBAAoB;CAsDjC,OApD6B,QAAc;EACzC,IAAI;EAYJ,OANI,MACF,IAAmB;GACjB,QAAQ;GACR,YAAY;GACb,GAEI,EAAc;GACnB,OAAO;IAAE,QAAQ;IAAa,YAAY;IAAiB;GAC3D,QAAQ;IAAE,QAAQ;IAAc,YAAY;IAAkB;GAC9D,aAAa;IACX,QAAQ;IACR,YAAY;IACb;GACD,mBAAmB;IACjB,QAAQ;IACR,YAAY;IACb;GACD,oBAAoB;IAClB,QAAQ;IACR,YAAY;IACb;GACD,qBAAqB;IACnB,QAAQ;IACR,YAAY;IACb;GACD;GACD,CAAC;IACD;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAEM,EAAsB"}
|
|
1
|
+
{"version":3,"file":"useBackofficeAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeAuth.ts"],"sourcesContent":["import { useCallback, useMemo, useState } from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLTaggedNode, PayloadError } from 'relay-runtime';\n\nimport {\n createUseAuth,\n type UseAuthReturn,\n type AcceptInvitationResponse,\n type AcceptInvitationVariables,\n type BeginAuthenticationResponse,\n type BeginAuthenticationVariables,\n type BeginPasskeyLoginResponse,\n type BeginPasskeyLoginVariables,\n type CompleteMfaResponse,\n type CompleteMfaVariables,\n type FinishPasskeyLoginResponse,\n type FinishPasskeyLoginVariables,\n type LoginResponse,\n type LoginVariables,\n type LogoutResponse,\n type LogoutVariables,\n} from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport type { BackofficeLazyValue } from '../provider/lazyValue.js';\nimport { useRelayEnvironment } from '../relay/useRelayEnvironment.js';\n\nconst { commitMutation } = ReactRelay;\n\ntype MutationCommitConfig<TVariables, TResponse> = {\n variables: TVariables;\n onCompleted?: (\n response: TResponse,\n errors: readonly PayloadError[] | null,\n ) => void;\n onError?: (error: Error) => void;\n};\n\nconst toMutationLoadError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Unable to load auth mutation.');\n};\n\nconst useDeferredMutation = <TVariables extends object, TResponse>(\n loadMutation: () => Promise<GraphQLTaggedNode | null>,\n) => {\n const relayEnvironment = useRelayEnvironment();\n const [inFlightCount, setInFlightCount] = useState(0);\n\n const commit = useCallback(\n (config: MutationCommitConfig<TVariables, TResponse>) => {\n setInFlightCount((count) => {\n return count + 1;\n });\n\n const finish = () => {\n setInFlightCount((count) => {\n return Math.max(0, count - 1);\n });\n };\n\n loadMutation()\n .then((mutation) => {\n if (mutation == null) {\n throw new Error('Missing auth mutation config.');\n }\n\n commitMutation(relayEnvironment, {\n mutation,\n variables: config.variables,\n onCompleted: (response, errors) => {\n finish();\n config.onCompleted?.(response as TResponse, errors ?? null);\n },\n onError: (error) => {\n finish();\n config.onError?.(error);\n },\n });\n })\n .catch((error: unknown) => {\n finish();\n config.onError?.(toMutationLoadError(error));\n });\n },\n [loadMutation, relayEnvironment],\n );\n\n return {\n commit,\n isInFlight: inFlightCount > 0,\n };\n};\n\nconst loadOptionalMutation = async <TConfig>(\n eagerMutation: GraphQLTaggedNode | null | undefined,\n lazyConfig: BackofficeLazyValue<TConfig> | null | undefined,\n selectMutation: (config: TConfig) => GraphQLTaggedNode,\n): Promise<GraphQLTaggedNode | null> => {\n if (eagerMutation != null) {\n return eagerMutation;\n }\n if (lazyConfig == null) {\n return null;\n }\n const loadedConfig = await lazyConfig.load();\n return selectMutation(loadedConfig);\n};\n\n/**\n * Provides auth actions/state backed by Relay mutations from BackofficeProvider.\n */\nexport function useBackofficeAuth(): UseAuthReturn {\n const { auth: authConfig } = useBackofficeConfig();\n const { commit: commitLogin, isInFlight: isLoginInFlight } =\n useDeferredMutation<LoginVariables, LoginResponse>(\n useCallback(async () => {\n const loginConfig = authConfig.login.get();\n return loadOptionalMutation(\n loginConfig?.loginMutation,\n authConfig.login,\n (config) => {\n return config.loginMutation;\n },\n );\n }, [authConfig.login]),\n );\n const { commit: commitLogout, isInFlight: isLogoutInFlight } =\n useDeferredMutation<LogoutVariables, LogoutResponse>(\n useCallback(async () => {\n const logoutConfig = await authConfig.logout.load();\n return logoutConfig.logoutMutation;\n }, [authConfig.logout]),\n );\n const { commit: commitCompleteMfa, isInFlight: isCompleteMfaInFlight } =\n useDeferredMutation<CompleteMfaVariables, CompleteMfaResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.completeMfaMutation,\n authConfig.completeMfa,\n (config) => {\n return config.completeMfaMutation;\n },\n );\n }, [authConfig.completeMfa, authConfig.login]),\n );\n const {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n } = useDeferredMutation<\n BeginPasskeyLoginVariables,\n BeginPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.beginPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n } = useDeferredMutation<\n FinishPasskeyLoginVariables,\n FinishPasskeyLoginResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.finishPasskeyLoginMutation,\n authConfig.passkeyLogin,\n (config) => {\n return config.finishPasskeyLoginMutation;\n },\n );\n }, [authConfig.login, authConfig.passkeyLogin]),\n );\n const {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n } = useDeferredMutation<\n BeginAuthenticationVariables,\n BeginAuthenticationResponse\n >(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.beginAuthenticationMutation,\n authConfig.authentication,\n (config) => {\n return config.beginAuthenticationMutation;\n },\n );\n }, [authConfig.authentication, authConfig.login]),\n );\n const {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n } = useDeferredMutation<AcceptInvitationVariables, AcceptInvitationResponse>(\n useCallback(async () => {\n return loadOptionalMutation(\n authConfig.login.get()?.acceptInvitationMutation,\n authConfig.acceptInvitation,\n (config) => {\n return config.acceptInvitationMutation;\n },\n );\n }, [authConfig.acceptInvitation, authConfig.login]),\n );\n const hasAcceptInvitationMutation =\n authConfig.login.get()?.acceptInvitationMutation != null ||\n authConfig.acceptInvitation != null;\n\n const useAuthWithMutations = useMemo(() => {\n let acceptInvitation:\n | {\n commit: typeof commitAcceptInvitation;\n isInFlight: boolean;\n }\n | undefined;\n if (hasAcceptInvitationMutation) {\n acceptInvitation = {\n commit: commitAcceptInvitation,\n isInFlight: isAcceptInvitationInFlight,\n };\n }\n return createUseAuth({\n login: { commit: commitLogin, isInFlight: isLoginInFlight },\n logout: { commit: commitLogout, isInFlight: isLogoutInFlight },\n completeMfa: {\n commit: commitCompleteMfa,\n isInFlight: isCompleteMfaInFlight,\n },\n beginPasskeyLogin: {\n commit: commitBeginPasskeyLogin,\n isInFlight: isBeginPasskeyLoginInFlight,\n },\n finishPasskeyLogin: {\n commit: commitFinishPasskeyLogin,\n isInFlight: isFinishPasskeyLoginInFlight,\n },\n beginAuthentication: {\n commit: commitBeginAuthentication,\n isInFlight: isBeginAuthenticationInFlight,\n },\n acceptInvitation,\n });\n }, [\n commitAcceptInvitation,\n commitBeginAuthentication,\n commitBeginPasskeyLogin,\n commitCompleteMfa,\n commitFinishPasskeyLogin,\n commitLogin,\n commitLogout,\n hasAcceptInvitationMutation,\n isAcceptInvitationInFlight,\n isBeginAuthenticationInFlight,\n isBeginPasskeyLoginInFlight,\n isCompleteMfaInFlight,\n isFinishPasskeyLoginInFlight,\n isLoginInFlight,\n isLogoutInFlight,\n ]);\n\n return useAuthWithMutations();\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeInfiniteScrollSentinel.js","names":[],"sources":["../../../src/hooks/useBackofficeInfiniteScrollSentinel.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type UseBackofficeInfiniteScrollSentinelOptions = {\n enabled: boolean;\n hasNextPage: boolean;\n isLoading: boolean;\n root?: Element | null;\n rootMargin?: string;\n threshold?: number;\n onIntersect: () => void;\n};\n\nexport type UseBackofficeInfiniteScrollSentinelResult = {\n sentinelRef: (node: HTMLElement | null) => void;\n};\n\n/**\n * Observes a sentinel element and triggers pagination when it enters the viewport.\n */\nexport function useBackofficeInfiniteScrollSentinel({\n enabled,\n hasNextPage,\n isLoading,\n onIntersect,\n root = null,\n rootMargin = '360px 0px',\n threshold = 0,\n}: UseBackofficeInfiniteScrollSentinelOptions): UseBackofficeInfiniteScrollSentinelResult {\n const [node, setNode] = useState<HTMLElement | null>(null);\n const onIntersectRef = useRef(onIntersect);\n const lastIntersectAtRef = useRef(0);\n\n useEffect(() => {\n onIntersectRef.current = onIntersect;\n }, [onIntersect]);\n\n useEffect(() => {\n if (!enabled || !hasNextPage || isLoading || node == null) {\n return () => {};\n }\n\n const triggerIntersect = () => {\n const now = Date.now();\n if (now - lastIntersectAtRef.current < 250) {\n return;\n }\n lastIntersectAtRef.current = now;\n onIntersectRef.current();\n };\n\n if (typeof IntersectionObserver === 'undefined') {\n triggerIntersect();\n return () => {};\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting === true) {\n triggerIntersect();\n }\n },\n {\n root,\n rootMargin,\n threshold,\n },\n );\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, [enabled, hasNextPage, isLoading, node, root, rootMargin, threshold]);\n\n const sentinelRef = useCallback((next: HTMLElement | null) => {\n setNode(next);\n }, []);\n\n return { sentinelRef };\n}\n"],"mappings":";;AAmBA,SAAgB,EAAoC,EAClD,YACA,gBACA,cACA,gBACA,UAAO,MACP,gBAAa,aACb,eAAY,KAC4E;CACxF,IAAM,CAAC,GAAM,KAAW,EAA6B,
|
|
1
|
+
{"version":3,"file":"useBackofficeInfiniteScrollSentinel.js","names":[],"sources":["../../../src/hooks/useBackofficeInfiniteScrollSentinel.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport type UseBackofficeInfiniteScrollSentinelOptions = {\n enabled: boolean;\n hasNextPage: boolean;\n isLoading: boolean;\n root?: Element | null;\n rootMargin?: string;\n threshold?: number;\n onIntersect: () => void;\n};\n\nexport type UseBackofficeInfiniteScrollSentinelResult = {\n sentinelRef: (node: HTMLElement | null) => void;\n};\n\n/**\n * Observes a sentinel element and triggers pagination when it enters the viewport.\n */\nexport function useBackofficeInfiniteScrollSentinel({\n enabled,\n hasNextPage,\n isLoading,\n onIntersect,\n root = null,\n rootMargin = '360px 0px',\n threshold = 0,\n}: UseBackofficeInfiniteScrollSentinelOptions): UseBackofficeInfiniteScrollSentinelResult {\n const [node, setNode] = useState<HTMLElement | null>(null);\n const onIntersectRef = useRef(onIntersect);\n const lastIntersectAtRef = useRef(0);\n\n useEffect(() => {\n onIntersectRef.current = onIntersect;\n }, [onIntersect]);\n\n useEffect(() => {\n if (!enabled || !hasNextPage || isLoading || node == null) {\n return () => {};\n }\n\n const triggerIntersect = () => {\n const now = Date.now();\n if (now - lastIntersectAtRef.current < 250) {\n return;\n }\n lastIntersectAtRef.current = now;\n onIntersectRef.current();\n };\n\n if (typeof IntersectionObserver === 'undefined') {\n triggerIntersect();\n return () => {};\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n const entry = entries[0];\n if (entry?.isIntersecting === true) {\n triggerIntersect();\n }\n },\n {\n root,\n rootMargin,\n threshold,\n },\n );\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, [enabled, hasNextPage, isLoading, node, root, rootMargin, threshold]);\n\n const sentinelRef = useCallback((next: HTMLElement | null) => {\n setNode(next);\n }, []);\n\n return { sentinelRef };\n}\n"],"mappings":";;AAmBA,SAAgB,EAAoC,EAClD,YACA,gBACA,cACA,gBACA,UAAO,MACP,gBAAa,aACb,eAAY,KAC4E;CACxF,IAAM,CAAC,GAAM,KAAW,EAA6B,IAAI,GACnD,IAAiB,EAAO,CAAW,GACnC,IAAqB,EAAO,CAAC;CAkDnC,OAhDA,QAAgB;EACd,EAAe,UAAU;CAC3B,GAAG,CAAC,CAAW,CAAC,GAEhB,QAAgB;EACd,IAAI,CAAC,KAAW,CAAC,KAAe,KAAa,KAAQ,MACnD,aAAa,CAAC;EAGhB,IAAM,UAAyB;GAC7B,IAAM,IAAM,KAAK,IAAI;GACjB,IAAM,EAAmB,UAAU,QAGvC,EAAmB,UAAU,GAC7B,EAAe,QAAQ;EACzB;EAEA,IAAI,OAAO,uBAAyB,KAElC,OADA,EAAiB,SACJ,CAAC;EAGhB,IAAM,IAAW,IAAI,sBAClB,MAAY;GAEX,AADc,EAAQ,IACX,mBAAmB,MAC5B,EAAiB;EAErB,GACA;GACE;GACA;GACA;EACF,CACF;EAIA,OAFA,EAAS,QAAQ,CAAI,SAER;GACX,EAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAS;EAAa;EAAW;EAAM;EAAM;EAAY;CAAS,CAAC,GAMhE,EAAE,aAJW,GAAa,MAA6B;EAC5D,EAAQ,CAAI;CACd,GAAG,CAAC,CAEK,EAAY;AACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeListRefetch.js","names":[],"sources":["../../../src/hooks/useBackofficeListRefetch.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: {\n fetchPolicy: FetchPolicy;\n onComplete?: (error: Error | null) => void;\n },\n) => { dispose: () => void } | undefined;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildQueryVariables: (\n input: BackofficeListVariables<Where, Sort>,\n ) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n defaults,\n fetchPolicy,\n buildQueryVariables,\n}: Params<Where, Sort, Variables>): {\n isRefreshing: boolean;\n onRefresh: () => void;\n} {\n const [isRefreshing, setIsRefreshing] = useState(false);\n const requestIdRef = useRef(0);\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: defaults.where,\n sort: defaults.sort,\n count: defaults.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n return buildQueryVariables(input);\n },\n [buildQueryVariables],\n );\n\n const runRefetch = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n const requestId = requestIdRef.current + 1;\n requestIdRef.current = requestId;\n setIsRefreshing(true);\n\n const nextVariables = resolveVariables({ ...input, cursor: null });\n try {\n startTransition(() => {\n refetch(nextVariables, {\n fetchPolicy,\n onComplete: () => {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n },\n });\n });\n } catch (error) {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n throw error;\n }\n },\n [fetchPolicy, refetch, resolveVariables],\n );\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n const onRefresh = useCallback(() => {\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n return { isRefreshing, onRefresh };\n}\n"],"mappings":";;;AAqCA,SAAgB,EAId,EACA,YACA,cACA,aACA,gBACA,0BAIA;CACA,IAAM,CAAC,GAAc,KAAmB,EAAS,
|
|
1
|
+
{"version":3,"file":"useBackofficeListRefetch.js","names":[],"sources":["../../../src/hooks/useBackofficeListRefetch.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport type { FetchPolicy } from 'relay-runtime';\n\nimport { stableListVariablesKey } from '@plumile/backoffice-core/state/stableKey.js';\nimport type { BackofficeListVariables } from '@plumile/backoffice-core/types.js';\n\ntype RefetchFn<TVariables> = (\n vars: TVariables,\n opts: {\n fetchPolicy: FetchPolicy;\n onComplete?: (error: Error | null) => void;\n },\n) => { dispose: () => void } | undefined;\n\ntype Params<Where, Sort extends string, Variables> = {\n refetch: RefetchFn<Variables>;\n variables: BackofficeListVariables<Where, Sort>;\n defaults: BackofficeListVariables<Where, Sort>;\n fetchPolicy: FetchPolicy;\n buildQueryVariables: (\n input: BackofficeListVariables<Where, Sort>,\n ) => Variables;\n};\n\n/**\n * Standardizes refetch behavior for backoffice list components:\n * - Refetches when list URL state changes (where/sort/count), gated by a stable key.\n * - Exposes a manual refresh callback using the same variables.\n *\n * This hook must not call Relay hooks (`useFragment`, `usePaginationFragment`, ...).\n */\nexport function useBackofficeListRefetch<\n Where,\n Sort extends string,\n Variables extends Record<string, unknown>,\n>({\n refetch,\n variables,\n defaults,\n fetchPolicy,\n buildQueryVariables,\n}: Params<Where, Sort, Variables>): {\n isRefreshing: boolean;\n onRefresh: () => void;\n} {\n const [isRefreshing, setIsRefreshing] = useState(false);\n const requestIdRef = useRef(0);\n const lastRefetchKeyRef = useRef<string | null>(\n stableListVariablesKey({\n where: defaults.where,\n sort: defaults.sort,\n count: defaults.count,\n }),\n );\n\n const resolveVariables = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n return buildQueryVariables(input);\n },\n [buildQueryVariables],\n );\n\n const runRefetch = useCallback(\n (input: BackofficeListVariables<Where, Sort>) => {\n const requestId = requestIdRef.current + 1;\n requestIdRef.current = requestId;\n setIsRefreshing(true);\n\n const nextVariables = resolveVariables({ ...input, cursor: null });\n try {\n startTransition(() => {\n refetch(nextVariables, {\n fetchPolicy,\n onComplete: () => {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n },\n });\n });\n } catch (error) {\n if (requestIdRef.current === requestId) {\n setIsRefreshing(false);\n }\n throw error;\n }\n },\n [fetchPolicy, refetch, resolveVariables],\n );\n\n useEffect(() => {\n const key = stableListVariablesKey({\n where: variables.where,\n sort: variables.sort,\n count: variables.count,\n });\n if (lastRefetchKeyRef.current === key) {\n return;\n }\n lastRefetchKeyRef.current = key;\n\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n const onRefresh = useCallback(() => {\n runRefetch(variables);\n }, [runRefetch, variables]);\n\n return { isRefreshing, onRefresh };\n}\n"],"mappings":";;;AAqCA,SAAgB,EAId,EACA,YACA,cACA,aACA,gBACA,0BAIA;CACA,IAAM,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,IAAe,EAAO,CAAC,GACvB,IAAoB,EACxB,EAAuB;EACrB,OAAO,EAAS;EAChB,MAAM,EAAS;EACf,OAAO,EAAS;CAClB,CAAC,CACH,GAEM,IAAmB,GACtB,MACQ,EAAoB,CAAK,GAElC,CAAC,CAAmB,CACtB,GAEM,IAAa,GAChB,MAAgD;EAC/C,IAAM,IAAY,EAAa,UAAU;EAEzC,AADA,EAAa,UAAU,GACvB,EAAgB,EAAI;EAEpB,IAAM,IAAgB,EAAiB;GAAE,GAAG;GAAO,QAAQ;EAAK,CAAC;EACjE,IAAI;GACF,QAAsB;IACpB,EAAQ,GAAe;KACrB;KACA,kBAAkB;MAChB,AAAI,EAAa,YAAY,KAC3B,EAAgB,EAAK;KAEzB;IACF,CAAC;GACH,CAAC;EACH,SAAS,GAAO;GAId,MAHI,EAAa,YAAY,KAC3B,EAAgB,EAAK,GAEjB;EACR;CACF,GACA;EAAC;EAAa;EAAS;CAAgB,CACzC;CAoBA,OAlBA,QAAgB;EACd,IAAM,IAAM,EAAuB;GACjC,OAAO,EAAU;GACjB,MAAM,EAAU;GAChB,OAAO,EAAU;EACnB,CAAC;EACG,EAAkB,YAAY,MAGlC,EAAkB,UAAU,GAE5B,EAAW,CAAS;CACtB,GAAG,CAAC,GAAY,CAAS,CAAC,GAMnB;EAAE;EAAc,WAJL,QAAkB;GAClC,EAAW,CAAS;EACtB,GAAG,CAAC,GAAY,CAAS,CAEF;CAAU;AACnC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const params = config.listUrlCodec.serialize(next as never);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"useBackofficeListUrlState.js","names":[],"sources":["../../../src/hooks/useBackofficeListUrlState.ts"],"sourcesContent":["import { useCallback, useContext, useMemo } from 'react';\nimport RoutingContext from '@plumile/router/routing/RoutingContext.js';\nimport useLocation from '@plumile/router/routing/useLocation.js';\n\nimport type {\n BackofficeListState,\n BackofficeRuntimeResolvedListFacetConfig,\n} from '@plumile/backoffice-core/types.js';\n\n/** Normalizes a router `location.search` string into URLSearchParams. */\nfunction normalizeSearch(value: string): URLSearchParams {\n if (value.trim() === '') {\n return new URLSearchParams();\n }\n return new URLSearchParams(value);\n}\n\ntype ReturnValue<Where extends Record<string, unknown>, Sort extends string> = {\n state: BackofficeListState<Where, Sort>;\n pushState: (next: BackofficeListState<Where, Sort>) => void;\n};\n\n/** Keeps list state in sync with the URL search params for backoffice pages. */\nexport function useBackofficeListUrlState<\n Where extends Record<string, unknown>,\n Sort extends string,\n>(config: BackofficeRuntimeResolvedListFacetConfig): ReturnValue<Where, Sort> {\n const routing = useContext(RoutingContext);\n const { hash, pathname, search } = useLocation();\n const fallbackState = useMemo(() => {\n return {\n where: null,\n sort: null,\n };\n }, []);\n\n const state = useMemo(() => {\n if (config.listUrlCodec == null) {\n return fallbackState;\n }\n return config.listUrlCodec.parse(\n normalizeSearch(search),\n ) as BackofficeListState<Where, Sort>;\n }, [config.listUrlCodec, fallbackState, search]);\n\n const pushState = useCallback(\n (next: BackofficeListState<Where, Sort>) => {\n if (routing == null) {\n return;\n }\n if (config.listUrlCodec == null) {\n return;\n }\n\n const params = config.listUrlCodec.serialize(next as never);\n const qs = params.toString();\n\n let nextSearch = '';\n if (qs !== '') {\n nextSearch = `?${qs}`;\n }\n\n routing.history.push({\n pathname,\n search: nextSearch,\n hash,\n });\n },\n [config.listUrlCodec, hash, pathname, routing],\n );\n\n return { state, pushState };\n}\n"],"mappings":";;;;AAUA,SAAS,EAAgB,GAAgC;CAIvD,OAHI,EAAM,KAAK,MAAM,KACZ,IAAI,gBAAgB,IAEtB,IAAI,gBAAgB,CAAK;AAClC;AAQA,SAAgB,EAGd,GAA4E;CAC5E,IAAM,IAAU,EAAW,CAAc,GACnC,EAAE,SAAM,aAAU,cAAW,EAAY,GACzC,IAAgB,SACb;EACL,OAAO;EACP,MAAM;CACR,IACC,CAAC,CAAC;CAqCL,OAAO;EAAE,OAnCK,QACR,EAAO,gBAAgB,OAClB,IAEF,EAAO,aAAa,MACzB,EAAgB,CAAM,CACxB,GACC;GAAC,EAAO;GAAc;GAAe;EAAM,CA4BrC;EAAO,WA1BE,GACf,MAA2C;GAI1C,IAHI,KAAW,QAGX,EAAO,gBAAgB,MACzB;GAIF,IAAM,IADS,EAAO,aAAa,UAAU,CAClC,EAAO,SAAS,GAEvB,IAAa;GAKjB,AAJI,MAAO,OACT,IAAa,IAAI,MAGnB,EAAQ,QAAQ,KAAK;IACnB;IACA,QAAQ;IACR;GACF,CAAC;EACH,GACA;GAAC,EAAO;GAAc;GAAM;GAAU;EAAO,CAG/B;CAAU;AAC5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeLoadMore.js","names":[],"sources":["../../../src/hooks/useBackofficeLoadMore.ts"],"sourcesContent":["import { startTransition, useCallback } from 'react';\n\ntype Params = {\n hasNext: boolean;\n isLoadingNext: boolean;\n loadNext: (count: number) => void;\n count: number;\n};\n\n/**\n * Wraps Relay `loadNext()` with consistent guards and `startTransition()`.\n */\nexport function useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count,\n}: Params): () => void {\n return useCallback(() => {\n if (!hasNext || isLoadingNext) {\n return;\n }\n\n startTransition(() => {\n loadNext(count);\n });\n }, [count, hasNext, isLoadingNext, loadNext]);\n}\n"],"mappings":";;AAYA,SAAgB,EAAsB,EACpC,YACA,kBACA,aACA,YACqB;CACrB,OAAO,QAAkB;EACnB,CAAC,KAAW,KAIhB,QAAsB;GACpB,EAAS,
|
|
1
|
+
{"version":3,"file":"useBackofficeLoadMore.js","names":[],"sources":["../../../src/hooks/useBackofficeLoadMore.ts"],"sourcesContent":["import { startTransition, useCallback } from 'react';\n\ntype Params = {\n hasNext: boolean;\n isLoadingNext: boolean;\n loadNext: (count: number) => void;\n count: number;\n};\n\n/**\n * Wraps Relay `loadNext()` with consistent guards and `startTransition()`.\n */\nexport function useBackofficeLoadMore({\n hasNext,\n isLoadingNext,\n loadNext,\n count,\n}: Params): () => void {\n return useCallback(() => {\n if (!hasNext || isLoadingNext) {\n return;\n }\n\n startTransition(() => {\n loadNext(count);\n });\n }, [count, hasNext, isLoadingNext, loadNext]);\n}\n"],"mappings":";;AAYA,SAAgB,EAAsB,EACpC,YACA,kBACA,aACA,YACqB;CACrB,OAAO,QAAkB;EACnB,CAAC,KAAW,KAIhB,QAAsB;GACpB,EAAS,CAAK;EAChB,CAAC;CACH,GAAG;EAAC;EAAO;EAAS;EAAe;CAAQ,CAAC;AAC9C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeSessionAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeSessionAuth.ts"],"sourcesContent":["import * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\n\nimport type { LogoutResponse, LogoutVariables } from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthLogoutConfig } from '../provider/useBackofficeLazyValue.js';\n\nconst { useMutation } = ReactRelay;\n\nconst toLogoutCleanupError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Logout cleanup failed.');\n};\n\nexport type BackofficeSessionAuth = {\n logout: () => Promise<void>;\n isLoading: boolean;\n};\n\nexport const useBackofficeSessionAuth = (): BackofficeSessionAuth => {\n const { auth: authConfig } = useBackofficeConfig();\n const auth = useBackofficeAuthLogoutConfig();\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n const [commitLogout, isLogoutInFlight] = useMutation<LogoutMutation>(\n auth.logoutMutation,\n );\n\n return {\n logout: async () => {\n return new Promise((resolve, reject) => {\n commitLogout({\n variables: {},\n onCompleted: () => {\n Promise.resolve(authConfig.lifecycle?.onLogoutSuccess?.()).then(\n () => {\n resolve();\n },\n (error: unknown) => {\n reject(toLogoutCleanupError(error));\n },\n );\n },\n onError: (error) => {\n if (error instanceof Error) {\n reject(error);\n return;\n }\n reject(new Error('Logout failed.'));\n },\n });\n });\n },\n isLoading: isLogoutInFlight,\n };\n};\n\nexport default useBackofficeSessionAuth;\n"],"mappings":";;;;AAOA,IAAM,EAAE,mBAAgB,GAElB,KAAwB,MACxB,aAAiB,QACZ,IAEF,gBAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"useBackofficeSessionAuth.js","names":[],"sources":["../../../src/hooks/useBackofficeSessionAuth.ts"],"sourcesContent":["import * as ReactRelay from 'react-relay';\nimport type { MutationParameters } from 'relay-runtime';\n\nimport type { LogoutResponse, LogoutVariables } from './useAuth.js';\nimport { useBackofficeConfig } from '../provider/BackofficeConfigContext.js';\nimport { useBackofficeAuthLogoutConfig } from '../provider/useBackofficeLazyValue.js';\n\nconst { useMutation } = ReactRelay;\n\nconst toLogoutCleanupError = (error: unknown): Error => {\n if (error instanceof Error) {\n return error;\n }\n return new Error('Logout cleanup failed.');\n};\n\nexport type BackofficeSessionAuth = {\n logout: () => Promise<void>;\n isLoading: boolean;\n};\n\nexport const useBackofficeSessionAuth = (): BackofficeSessionAuth => {\n const { auth: authConfig } = useBackofficeConfig();\n const auth = useBackofficeAuthLogoutConfig();\n\n type LogoutMutation = MutationParameters & {\n response: LogoutResponse;\n variables: LogoutVariables;\n };\n\n const [commitLogout, isLogoutInFlight] = useMutation<LogoutMutation>(\n auth.logoutMutation,\n );\n\n return {\n logout: async () => {\n return new Promise((resolve, reject) => {\n commitLogout({\n variables: {},\n onCompleted: () => {\n Promise.resolve(authConfig.lifecycle?.onLogoutSuccess?.()).then(\n () => {\n resolve();\n },\n (error: unknown) => {\n reject(toLogoutCleanupError(error));\n },\n );\n },\n onError: (error) => {\n if (error instanceof Error) {\n reject(error);\n return;\n }\n reject(new Error('Logout failed.'));\n },\n });\n });\n },\n isLoading: isLogoutInFlight,\n };\n};\n\nexport default useBackofficeSessionAuth;\n"],"mappings":";;;;AAOA,IAAM,EAAE,mBAAgB,GAElB,KAAwB,MACxB,aAAiB,QACZ,IAEF,gBAAI,MAAM,wBAAwB,GAQ9B,UAAwD;CACnE,IAAM,EAAE,MAAM,MAAe,EAAoB,GAQ3C,CAAC,GAAc,KAAoB,EAP5B,EAQX,EAAK,cACP;CAEA,OAAO;EACL,QAAQ,YACC,IAAI,SAAS,GAAS,MAAW;GACtC,EAAa;IACX,WAAW,CAAC;IACZ,mBAAmB;KACjB,QAAQ,QAAQ,EAAW,WAAW,kBAAkB,CAAC,EAAE,WACnD;MACJ,EAAQ;KACV,IACC,MAAmB;MAClB,EAAO,EAAqB,CAAK,CAAC;KACpC,CACF;IACF;IACA,UAAU,MAAU;KAClB,IAAI,aAAiB,OAAO;MAC1B,EAAO,CAAK;MACZ;KACF;KACA,EAAO,gBAAI,MAAM,gBAAgB,CAAC;IACpC;GACF,CAAC;EACH,CAAC;EAEH,WAAW;CACb;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBackofficeSidebarPins.js","names":[],"sources":["../../../src/hooks/useBackofficeSidebarPins.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nconst DEFAULT_STORAGE_KEY = 'backoffice.sidebar.pins.v1';\n\ntype PinsPayload = unknown;\n\nconst readPinsFromStorage = (storageKey: string): string[] => {\n if (typeof window === 'undefined') {\n return [];\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return [];\n }\n const parsed = JSON.parse(raw) as PinsPayload;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((entry): entry is string => {\n return typeof entry === 'string';\n });\n } catch {\n return [];\n }\n};\n\nconst normalizePins = (\n pins: readonly string[],\n validIds: Set<string>,\n): string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n pins.forEach((entry) => {\n if (!validIds.has(entry)) {\n return;\n }\n if (seen.has(entry)) {\n return;\n }\n seen.add(entry);\n output.push(entry);\n });\n return output;\n};\n\nconst reorderPins = (\n pins: readonly string[],\n fromId: string,\n toId: string,\n): readonly string[] => {\n if (fromId === toId) {\n return pins;\n }\n const fromIndex = pins.indexOf(fromId);\n const toIndex = pins.indexOf(toId);\n if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {\n return pins;\n }\n const next = [...pins];\n next.splice(fromIndex, 1);\n next.splice(toIndex, 0, fromId);\n return next;\n};\n\nexport type SidebarPinsState = {\n pins: readonly string[];\n isPinned: (id: string) => boolean;\n pin: (id: string) => void;\n unpin: (id: string) => void;\n toggle: (id: string) => void;\n reorder: (fromId: string, toId: string) => void;\n};\n\nexport type UseBackofficeSidebarPinsInput = {\n enabled?: boolean;\n storageKey?: string;\n visibleEntityIds: readonly string[];\n};\n\nexport const useBackofficeSidebarPins = (\n input: UseBackofficeSidebarPinsInput,\n): SidebarPinsState => {\n const {\n enabled = true,\n storageKey = DEFAULT_STORAGE_KEY,\n visibleEntityIds,\n } = input;\n const validIds = useMemo(() => {\n return new Set(visibleEntityIds);\n }, [visibleEntityIds]);\n\n const [pins, setPins] = useState<string[]>(() => {\n if (!enabled) {\n return [];\n }\n const stored = readPinsFromStorage(storageKey);\n return normalizePins(stored, validIds);\n });\n\n useEffect(() => {\n if (!enabled) {\n setPins([]);\n return;\n }\n setPins((prev) => {\n const normalized = normalizePins(prev, validIds);\n if (normalized.length === prev.length) {\n let unchanged = true;\n for (let index = 0; index < normalized.length; index += 1) {\n if (normalized[index] !== prev[index]) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n return prev;\n }\n }\n return normalized;\n });\n }, [enabled, validIds]);\n\n useEffect(() => {\n if (!enabled) {\n setPins([]);\n return;\n }\n const stored = readPinsFromStorage(storageKey);\n setPins(normalizePins(stored, validIds));\n }, [enabled, storageKey, validIds]);\n\n useEffect(() => {\n if (!enabled || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(pins));\n } catch {\n // Ignore storage errors in non-browser or restricted environments.\n }\n }, [enabled, pins, storageKey]);\n\n const pinsSet = useMemo(() => {\n return new Set(pins);\n }, [pins]);\n\n const pin = useCallback(\n (id: string) => {\n if (!enabled) {\n return;\n }\n if (!validIds.has(id)) {\n return;\n }\n setPins((prev) => {\n if (prev.includes(id)) {\n return prev;\n }\n return [...prev, id];\n });\n },\n [enabled, validIds],\n );\n\n const unpin = useCallback(\n (id: string) => {\n if (!enabled) {\n return;\n }\n setPins((prev) => {\n return prev.filter((entry) => {\n return entry !== id;\n });\n });\n },\n [enabled],\n );\n\n const toggle = useCallback(\n (id: string) => {\n if (pinsSet.has(id)) {\n unpin(id);\n } else {\n pin(id);\n }\n },\n [pin, pinsSet, unpin],\n );\n\n const reorder = useCallback(\n (fromId: string, toId: string) => {\n if (!enabled) {\n return;\n }\n setPins((prev) => {\n return reorderPins(prev, fromId, toId) as string[];\n });\n },\n [enabled],\n );\n\n const isPinned = useCallback(\n (id: string) => {\n return pinsSet.has(id);\n },\n [pinsSet],\n );\n\n return {\n pins,\n isPinned,\n pin,\n unpin,\n toggle,\n reorder,\n };\n};\n\nexport const __test = {\n normalizePins,\n readPinsFromStorage,\n reorderPins,\n};\n\nexport default useBackofficeSidebarPins;\n"],"mappings":";;AAEA,IAAM,IAAsB,8BAItB,KAAuB,MAAiC;CAC5D,IAAI,OAAO,SAAW,KACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"useBackofficeSidebarPins.js","names":[],"sources":["../../../src/hooks/useBackofficeSidebarPins.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nconst DEFAULT_STORAGE_KEY = 'backoffice.sidebar.pins.v1';\n\ntype PinsPayload = unknown;\n\nconst readPinsFromStorage = (storageKey: string): string[] => {\n if (typeof window === 'undefined') {\n return [];\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return [];\n }\n const parsed = JSON.parse(raw) as PinsPayload;\n if (!Array.isArray(parsed)) {\n return [];\n }\n return parsed.filter((entry): entry is string => {\n return typeof entry === 'string';\n });\n } catch {\n return [];\n }\n};\n\nconst normalizePins = (\n pins: readonly string[],\n validIds: Set<string>,\n): string[] => {\n const output: string[] = [];\n const seen = new Set<string>();\n pins.forEach((entry) => {\n if (!validIds.has(entry)) {\n return;\n }\n if (seen.has(entry)) {\n return;\n }\n seen.add(entry);\n output.push(entry);\n });\n return output;\n};\n\nconst reorderPins = (\n pins: readonly string[],\n fromId: string,\n toId: string,\n): readonly string[] => {\n if (fromId === toId) {\n return pins;\n }\n const fromIndex = pins.indexOf(fromId);\n const toIndex = pins.indexOf(toId);\n if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) {\n return pins;\n }\n const next = [...pins];\n next.splice(fromIndex, 1);\n next.splice(toIndex, 0, fromId);\n return next;\n};\n\nexport type SidebarPinsState = {\n pins: readonly string[];\n isPinned: (id: string) => boolean;\n pin: (id: string) => void;\n unpin: (id: string) => void;\n toggle: (id: string) => void;\n reorder: (fromId: string, toId: string) => void;\n};\n\nexport type UseBackofficeSidebarPinsInput = {\n enabled?: boolean;\n storageKey?: string;\n visibleEntityIds: readonly string[];\n};\n\nexport const useBackofficeSidebarPins = (\n input: UseBackofficeSidebarPinsInput,\n): SidebarPinsState => {\n const {\n enabled = true,\n storageKey = DEFAULT_STORAGE_KEY,\n visibleEntityIds,\n } = input;\n const validIds = useMemo(() => {\n return new Set(visibleEntityIds);\n }, [visibleEntityIds]);\n\n const [pins, setPins] = useState<string[]>(() => {\n if (!enabled) {\n return [];\n }\n const stored = readPinsFromStorage(storageKey);\n return normalizePins(stored, validIds);\n });\n\n useEffect(() => {\n if (!enabled) {\n setPins([]);\n return;\n }\n setPins((prev) => {\n const normalized = normalizePins(prev, validIds);\n if (normalized.length === prev.length) {\n let unchanged = true;\n for (let index = 0; index < normalized.length; index += 1) {\n if (normalized[index] !== prev[index]) {\n unchanged = false;\n break;\n }\n }\n if (unchanged) {\n return prev;\n }\n }\n return normalized;\n });\n }, [enabled, validIds]);\n\n useEffect(() => {\n if (!enabled) {\n setPins([]);\n return;\n }\n const stored = readPinsFromStorage(storageKey);\n setPins(normalizePins(stored, validIds));\n }, [enabled, storageKey, validIds]);\n\n useEffect(() => {\n if (!enabled || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(storageKey, JSON.stringify(pins));\n } catch {\n // Ignore storage errors in non-browser or restricted environments.\n }\n }, [enabled, pins, storageKey]);\n\n const pinsSet = useMemo(() => {\n return new Set(pins);\n }, [pins]);\n\n const pin = useCallback(\n (id: string) => {\n if (!enabled) {\n return;\n }\n if (!validIds.has(id)) {\n return;\n }\n setPins((prev) => {\n if (prev.includes(id)) {\n return prev;\n }\n return [...prev, id];\n });\n },\n [enabled, validIds],\n );\n\n const unpin = useCallback(\n (id: string) => {\n if (!enabled) {\n return;\n }\n setPins((prev) => {\n return prev.filter((entry) => {\n return entry !== id;\n });\n });\n },\n [enabled],\n );\n\n const toggle = useCallback(\n (id: string) => {\n if (pinsSet.has(id)) {\n unpin(id);\n } else {\n pin(id);\n }\n },\n [pin, pinsSet, unpin],\n );\n\n const reorder = useCallback(\n (fromId: string, toId: string) => {\n if (!enabled) {\n return;\n }\n setPins((prev) => {\n return reorderPins(prev, fromId, toId) as string[];\n });\n },\n [enabled],\n );\n\n const isPinned = useCallback(\n (id: string) => {\n return pinsSet.has(id);\n },\n [pinsSet],\n );\n\n return {\n pins,\n isPinned,\n pin,\n unpin,\n toggle,\n reorder,\n };\n};\n\nexport const __test = {\n normalizePins,\n readPinsFromStorage,\n reorderPins,\n};\n\nexport default useBackofficeSidebarPins;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConditionalSubscription.js","names":[],"sources":["../../../src/hooks/useConditionalSubscription.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLSubscriptionConfig, OperationType } from 'relay-runtime';\n\nimport {\n getRelayTransportSnapshot,\n subscribeRelayTransport,\n} from '../relay/environment.js';\n\ntype ConditionalOptions<T extends OperationType> = {\n enabled: boolean;\n deps?: readonly unknown[];\n getVariables?: () => T['variables'];\n};\n\ntype UseConditionalSubscriptionReturn = {\n active: boolean;\n completed: boolean;\n error: Error | null;\n};\n\ntype Hop = { dispose: () => void } | null;\n\nconst EMPTY_DEPS: readonly unknown[] = [];\n\n/** Resolve the Relay module regardless of whether the package exposes a default export shim. */\nfunction resolveRelayApi(): typeof ReactRelay {\n const relayDefault: unknown = Reflect.get(ReactRelay, 'default');\n if (relayDefault != null) {\n return relayDefault as typeof ReactRelay;\n }\n return ReactRelay;\n}\n\nconst relayApi = resolveRelayApi();\n\n/** Subscribe only when the caller enables the subscription and variables exist. */\nexport function useConditionalSubscription<T extends OperationType>(\n config: GraphQLSubscriptionConfig<T>,\n options: ConditionalOptions<T>,\n): UseConditionalSubscriptionReturn {\n const environment = relayApi.useRelayEnvironment();\n const [error, setError] = useState<Error | null>(null);\n const [isSubscribed, setIsSubscribed] = useState(false);\n const [completed, setCompleted] = useState(false);\n const transportGeneration = useSyncExternalStore(\n subscribeRelayTransport,\n () => {\n return getRelayTransportSnapshot().generation;\n },\n () => {\n return getRelayTransportSnapshot().generation;\n },\n );\n\n const { enabled = true, deps = EMPTY_DEPS, getVariables } = options;\n\n const resolveVariables = useCallback((): T['variables'] | null => {\n try {\n if (getVariables != null) {\n return getVariables();\n }\n return config.variables;\n } catch {\n return null;\n }\n }, [config.variables, getVariables]);\n\n const resolvedVariables = useMemo<T['variables'] | null>(() => {\n return resolveVariables();\n }, [resolveVariables]);\n\n const stableVarsString = useMemo(() => {\n if (resolvedVariables == null) {\n return null;\n }\n try {\n return JSON.stringify(resolvedVariables);\n } catch {\n return null;\n }\n }, [resolvedVariables]);\n\n const isEnabled = Boolean(enabled);\n const variables = resolvedVariables;\n const canSubscribe = isEnabled && variables != null;\n const active = canSubscribe && isSubscribed && error == null && !completed;\n\n const disposableRef = useRef<Hop>(null);\n\n useEffect(() => {\n let disposable: Hop = null;\n const variables = resolveVariables();\n\n if (isEnabled && variables != null) {\n setError(null);\n setCompleted(false);\n setIsSubscribed(true);\n\n disposable = relayApi.requestSubscription<T>(environment, {\n subscription: config.subscription,\n variables,\n cacheConfig: config.cacheConfig,\n configs: config.configs,\n onCompleted: () => {\n setCompleted(true);\n setIsSubscribed(false);\n config.onCompleted?.();\n },\n onError: (nextError) => {\n setError(nextError);\n setIsSubscribed(false);\n config.onError?.(nextError);\n },\n onNext: config.onNext,\n updater: config.updater,\n });\n\n disposableRef.current = disposable;\n }\n\n return () => {\n setIsSubscribed(false);\n if (disposable != null) {\n try {\n disposable.dispose();\n } catch {\n // ignore cleanup failures\n }\n }\n if (disposableRef.current === disposable) {\n disposableRef.current = null;\n }\n };\n }, [\n config,\n deps,\n environment,\n isEnabled,\n resolveVariables,\n stableVarsString,\n transportGeneration,\n ]);\n\n return { active, completed, error };\n}\n"],"mappings":";;;;AA8BA,IAAM,IAAiC,
|
|
1
|
+
{"version":3,"file":"useConditionalSubscription.js","names":[],"sources":["../../../src/hooks/useConditionalSubscription.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport * as ReactRelay from 'react-relay';\nimport type { GraphQLSubscriptionConfig, OperationType } from 'relay-runtime';\n\nimport {\n getRelayTransportSnapshot,\n subscribeRelayTransport,\n} from '../relay/environment.js';\n\ntype ConditionalOptions<T extends OperationType> = {\n enabled: boolean;\n deps?: readonly unknown[];\n getVariables?: () => T['variables'];\n};\n\ntype UseConditionalSubscriptionReturn = {\n active: boolean;\n completed: boolean;\n error: Error | null;\n};\n\ntype Hop = { dispose: () => void } | null;\n\nconst EMPTY_DEPS: readonly unknown[] = [];\n\n/** Resolve the Relay module regardless of whether the package exposes a default export shim. */\nfunction resolveRelayApi(): typeof ReactRelay {\n const relayDefault: unknown = Reflect.get(ReactRelay, 'default');\n if (relayDefault != null) {\n return relayDefault as typeof ReactRelay;\n }\n return ReactRelay;\n}\n\nconst relayApi = resolveRelayApi();\n\n/** Subscribe only when the caller enables the subscription and variables exist. */\nexport function useConditionalSubscription<T extends OperationType>(\n config: GraphQLSubscriptionConfig<T>,\n options: ConditionalOptions<T>,\n): UseConditionalSubscriptionReturn {\n const environment = relayApi.useRelayEnvironment();\n const [error, setError] = useState<Error | null>(null);\n const [isSubscribed, setIsSubscribed] = useState(false);\n const [completed, setCompleted] = useState(false);\n const transportGeneration = useSyncExternalStore(\n subscribeRelayTransport,\n () => {\n return getRelayTransportSnapshot().generation;\n },\n () => {\n return getRelayTransportSnapshot().generation;\n },\n );\n\n const { enabled = true, deps = EMPTY_DEPS, getVariables } = options;\n\n const resolveVariables = useCallback((): T['variables'] | null => {\n try {\n if (getVariables != null) {\n return getVariables();\n }\n return config.variables;\n } catch {\n return null;\n }\n }, [config.variables, getVariables]);\n\n const resolvedVariables = useMemo<T['variables'] | null>(() => {\n return resolveVariables();\n }, [resolveVariables]);\n\n const stableVarsString = useMemo(() => {\n if (resolvedVariables == null) {\n return null;\n }\n try {\n return JSON.stringify(resolvedVariables);\n } catch {\n return null;\n }\n }, [resolvedVariables]);\n\n const isEnabled = Boolean(enabled);\n const variables = resolvedVariables;\n const canSubscribe = isEnabled && variables != null;\n const active = canSubscribe && isSubscribed && error == null && !completed;\n\n const disposableRef = useRef<Hop>(null);\n\n useEffect(() => {\n let disposable: Hop = null;\n const variables = resolveVariables();\n\n if (isEnabled && variables != null) {\n setError(null);\n setCompleted(false);\n setIsSubscribed(true);\n\n disposable = relayApi.requestSubscription<T>(environment, {\n subscription: config.subscription,\n variables,\n cacheConfig: config.cacheConfig,\n configs: config.configs,\n onCompleted: () => {\n setCompleted(true);\n setIsSubscribed(false);\n config.onCompleted?.();\n },\n onError: (nextError) => {\n setError(nextError);\n setIsSubscribed(false);\n config.onError?.(nextError);\n },\n onNext: config.onNext,\n updater: config.updater,\n });\n\n disposableRef.current = disposable;\n }\n\n return () => {\n setIsSubscribed(false);\n if (disposable != null) {\n try {\n disposable.dispose();\n } catch {\n // ignore cleanup failures\n }\n }\n if (disposableRef.current === disposable) {\n disposableRef.current = null;\n }\n };\n }, [\n config,\n deps,\n environment,\n isEnabled,\n resolveVariables,\n stableVarsString,\n transportGeneration,\n ]);\n\n return { active, completed, error };\n}\n"],"mappings":";;;;AA8BA,IAAM,IAAiC,CAAC;AAGxC,SAAS,IAAqC;CAK5C,OAJ8B,QAAQ,IAAI,GAAY,SAClD,KAGG;AACT;AAEA,IAAM,IAAW,EAAgB;AAGjC,SAAgB,EACd,GACA,GACkC;CAClC,IAAM,IAAc,EAAS,oBAAoB,GAC3C,CAAC,GAAO,KAAY,EAAuB,IAAI,GAC/C,CAAC,GAAc,KAAmB,EAAS,EAAK,GAChD,CAAC,GAAW,KAAgB,EAAS,EAAK,GAC1C,IAAsB,EAC1B,SAES,EAA0B,EAAE,kBAG5B,EAA0B,EAAE,UAEvC,GAEM,EAAE,aAAU,IAAM,UAAO,GAAY,oBAAiB,GAEtD,IAAmB,QAAyC;EAChE,IAAI;GAIF,OAHI,KAAgB,OAGb,EAAO,YAFL,EAAa;EAGxB,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,EAAO,WAAW,CAAY,CAAC,GAE7B,IAAoB,QACjB,EAAiB,GACvB,CAAC,CAAgB,CAAC,GAEf,IAAmB,QAAc;EACrC,IAAI,KAAqB,MACvB,OAAO;EAET,IAAI;GACF,OAAO,KAAK,UAAU,CAAiB;EACzC,QAAQ;GACN,OAAO;EACT;CACF,GAAG,CAAC,CAAiB,CAAC,GAEhB,IAAY,EAAQ,GAGpB,IADe,KAAa,KAAa,QAChB,KAAgB,KAAS,QAAQ,CAAC,GAE3D,IAAgB,EAAY,IAAI;CAwDtC,OAtDA,QAAgB;EACd,IAAI,IAAkB,MAChB,IAAY,EAAiB;EA6BnC,OA3BI,KAAa,KAAa,SAC5B,EAAS,IAAI,GACb,EAAa,EAAK,GAClB,EAAgB,EAAI,GAEpB,IAAa,EAAS,oBAAuB,GAAa;GACxD,cAAc,EAAO;GACrB;GACA,aAAa,EAAO;GACpB,SAAS,EAAO;GAChB,mBAAmB;IAGjB,AAFA,EAAa,EAAI,GACjB,EAAgB,EAAK,GACrB,EAAO,cAAc;GACvB;GACA,UAAU,MAAc;IAGtB,AAFA,EAAS,CAAS,GAClB,EAAgB,EAAK,GACrB,EAAO,UAAU,CAAS;GAC5B;GACA,QAAQ,EAAO;GACf,SAAS,EAAO;EAClB,CAAC,GAED,EAAc,UAAU,UAGb;GAEX,IADA,EAAgB,EAAK,GACjB,KAAc,MAChB,IAAI;IACF,EAAW,QAAQ;GACrB,QAAQ,CAER;GAEF,AAAI,EAAc,YAAY,MAC5B,EAAc,UAAU;EAE5B;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEM;EAAE;EAAQ;EAAW;CAAM;AACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCopyToClipboard.js","names":[],"sources":["../../../src/hooks/useCopyToClipboard.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst FALLBACK_TEXTAREA_ID = 'copy-to-clipboard-fallback';\n\n/** Write to the clipboard via a hidden textarea when the Clipboard API is unavailable. */\nfunction writeWithFallback(value: string): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n let textarea = document.getElementById(\n FALLBACK_TEXTAREA_ID,\n ) as HTMLTextAreaElement | null;\n\n if (textarea == null) {\n textarea = document.createElement('textarea');\n textarea.id = FALLBACK_TEXTAREA_ID;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'absolute';\n textarea.style.left = '-9999px';\n textarea.style.top = '0';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n }\n\n textarea.value = value;\n textarea.select();\n document.execCommand('copy');\n}\n\n/** Copy text with best-effort browser fallback and short-lived copied state. */\nexport function useCopyToClipboard(timeoutMs = 2000): {\n copiedKey: string | null;\n copy: (value: string, key?: string) => Promise<boolean>;\n} {\n const [copiedKey, setCopiedKey] = useState<string | null>(null);\n const timeoutRef = useRef<number | null>(null);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current != null) {\n window.clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n const copy = useCallback(\n async (value: string, key?: string): Promise<boolean> => {\n let succeeded = false;\n\n let clipboard: Clipboard | undefined;\n if (typeof navigator !== 'undefined') {\n clipboard = navigator.clipboard;\n }\n\n if (clipboard != null) {\n try {\n await clipboard.writeText(value);\n succeeded = true;\n } catch {\n succeeded = false;\n }\n }\n\n if (!succeeded) {\n writeWithFallback(value);\n succeeded = true;\n }\n\n if (key != null) {\n setCopiedKey(key);\n if (timeoutRef.current != null) {\n window.clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = window.setTimeout(() => {\n setCopiedKey(null);\n timeoutRef.current = null;\n }, timeoutMs);\n }\n\n return succeeded;\n },\n [timeoutMs],\n );\n\n return { copiedKey, copy };\n}\n\nexport default useCopyToClipboard;\n"],"mappings":";;AAEA,IAAM,IAAuB;AAG7B,SAAS,EAAkB,GAAqB;CAC9C,IAAI,OAAO,WAAa,KACtB;CAGF,IAAI,IAAW,SAAS,eACtB,
|
|
1
|
+
{"version":3,"file":"useCopyToClipboard.js","names":[],"sources":["../../../src/hooks/useCopyToClipboard.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nconst FALLBACK_TEXTAREA_ID = 'copy-to-clipboard-fallback';\n\n/** Write to the clipboard via a hidden textarea when the Clipboard API is unavailable. */\nfunction writeWithFallback(value: string): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n let textarea = document.getElementById(\n FALLBACK_TEXTAREA_ID,\n ) as HTMLTextAreaElement | null;\n\n if (textarea == null) {\n textarea = document.createElement('textarea');\n textarea.id = FALLBACK_TEXTAREA_ID;\n textarea.setAttribute('readonly', '');\n textarea.style.position = 'absolute';\n textarea.style.left = '-9999px';\n textarea.style.top = '0';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n }\n\n textarea.value = value;\n textarea.select();\n document.execCommand('copy');\n}\n\n/** Copy text with best-effort browser fallback and short-lived copied state. */\nexport function useCopyToClipboard(timeoutMs = 2000): {\n copiedKey: string | null;\n copy: (value: string, key?: string) => Promise<boolean>;\n} {\n const [copiedKey, setCopiedKey] = useState<string | null>(null);\n const timeoutRef = useRef<number | null>(null);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current != null) {\n window.clearTimeout(timeoutRef.current);\n }\n };\n }, []);\n\n const copy = useCallback(\n async (value: string, key?: string): Promise<boolean> => {\n let succeeded = false;\n\n let clipboard: Clipboard | undefined;\n if (typeof navigator !== 'undefined') {\n clipboard = navigator.clipboard;\n }\n\n if (clipboard != null) {\n try {\n await clipboard.writeText(value);\n succeeded = true;\n } catch {\n succeeded = false;\n }\n }\n\n if (!succeeded) {\n writeWithFallback(value);\n succeeded = true;\n }\n\n if (key != null) {\n setCopiedKey(key);\n if (timeoutRef.current != null) {\n window.clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = window.setTimeout(() => {\n setCopiedKey(null);\n timeoutRef.current = null;\n }, timeoutMs);\n }\n\n return succeeded;\n },\n [timeoutMs],\n );\n\n return { copiedKey, copy };\n}\n\nexport default useCopyToClipboard;\n"],"mappings":";;AAEA,IAAM,IAAuB;AAG7B,SAAS,EAAkB,GAAqB;CAC9C,IAAI,OAAO,WAAa,KACtB;CAGF,IAAI,IAAW,SAAS,eACtB,CACF;CAeA,AAbI,MACF,IAAW,SAAS,cAAc,UAAU,GAC5C,EAAS,KAAK,GACd,EAAS,aAAa,YAAY,EAAE,GACpC,EAAS,MAAM,WAAW,YAC1B,EAAS,MAAM,OAAO,WACtB,EAAS,MAAM,MAAM,KACrB,EAAS,MAAM,UAAU,KACzB,SAAS,KAAK,YAAY,CAAQ,IAGpC,EAAS,QAAQ,GACjB,EAAS,OAAO,GAChB,SAAS,YAAY,MAAM;AAC7B;AAGA,SAAgB,EAAmB,IAAY,KAG7C;CACA,IAAM,CAAC,GAAW,KAAgB,EAAwB,IAAI,GACxD,IAAa,EAAsB,IAAI;CAiD7C,OA/CA,cACe;EACX,AAAI,EAAW,WAAW,QACxB,OAAO,aAAa,EAAW,OAAO;CAE1C,GACC,CAAC,CAAC,GAyCE;EAAE;EAAW,MAvCP,EACX,OAAO,GAAe,MAAmC;GACvD,IAAI,IAAY,IAEZ;GAKJ,IAJI,OAAO,YAAc,QACvB,IAAY,UAAU,YAGpB,KAAa,MACf,IAAI;IAEF,AADA,MAAM,EAAU,UAAU,CAAK,GAC/B,IAAY;GACd,QAAQ;IACN,IAAY;GACd;GAmBF,OAhBA,AAEE,OADA,EAAkB,CAAK,GACX,KAGV,KAAO,SACT,EAAa,CAAG,GACZ,EAAW,WAAW,QACxB,OAAO,aAAa,EAAW,OAAO,GAExC,EAAW,UAAU,OAAO,iBAAiB;IAE3C,AADA,EAAa,IAAI,GACjB,EAAW,UAAU;GACvB,GAAG,CAAS,IAGP;EACT,GACA,CAAC,CAAS,CAGQ;CAAK;AAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useInfiniteConnection.js","names":[],"sources":["../../../src/hooks/useInfiniteConnection.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nexport type LoadMoreRunner = (\n onComplete: (error: Error | null) => void,\n) => void;\n\nexport type InfiniteConnectionTelemetryPayload = {\n surface: string;\n loadedCount?: number;\n durationMs?: number;\n};\n\nexport type InfiniteConnectionTelemetryEvent =\n | 'list_load_more_requested'\n | 'list_load_more_failed'\n | 'list_load_more_succeeded';\n\nexport type InfiniteConnectionErrorEvent = {\n scope: 'infinite_scroll' | 'infinite_scroll_timeout';\n message: string;\n payload: {\n surface: string;\n durationMs: number;\n };\n};\n\nexport type UseInfiniteConnectionParams<TNode> = {\n nodes: readonly TNode[];\n hasNext: boolean;\n isLoadingNext: boolean;\n runLoadMore: LoadMoreRunner;\n surface?: string;\n timeoutMs?: number;\n onTelemetry?: (\n event: InfiniteConnectionTelemetryEvent,\n payload: InfiniteConnectionTelemetryPayload,\n ) => void;\n onUiError?: (\n scope: InfiniteConnectionErrorEvent['scope'],\n message: string,\n payload: InfiniteConnectionErrorEvent['payload'],\n ) => void;\n onError?: (event: InfiniteConnectionErrorEvent) => void;\n};\n\nexport type UseInfiniteConnectionResult<TNode> = {\n nodes: readonly TNode[];\n hasNext: boolean;\n isLoadingNext: boolean;\n incrementalError: Error | null;\n loadMoreSafe: () => void;\n retryLoadMore: () => void;\n};\n\nexport const useInfiniteConnection = <TNode>({\n nodes,\n hasNext,\n isLoadingNext,\n runLoadMore,\n surface = 'unknown',\n timeoutMs = 15_000,\n onTelemetry,\n onUiError,\n onError,\n}: UseInfiniteConnectionParams<TNode>): UseInfiniteConnectionResult<TNode> => {\n const [incrementalError, setIncrementalError] = useState<Error | null>(null);\n const inFlightRef = useRef(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const requestTokenRef = useRef(0);\n\n const clearPendingTimeout = useCallback(() => {\n if (timeoutRef.current == null) {\n return;\n }\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }, []);\n\n useEffect(() => {\n return () => {\n clearPendingTimeout();\n };\n }, [clearPendingTimeout]);\n\n const loadMoreSafe = useCallback(() => {\n if (!hasNext || isLoadingNext || inFlightRef.current) {\n return;\n }\n inFlightRef.current = true;\n const requestToken = requestTokenRef.current + 1;\n requestTokenRef.current = requestToken;\n setIncrementalError(null);\n const startedAt = Date.now();\n onTelemetry?.('list_load_more_requested', {\n surface,\n loadedCount: nodes.length,\n });\n clearPendingTimeout();\n timeoutRef.current = setTimeout(() => {\n if (requestTokenRef.current !== requestToken) {\n return;\n }\n requestTokenRef.current = requestToken + 1;\n inFlightRef.current = false;\n setIncrementalError(new Error('timeout'));\n onTelemetry?.('list_load_more_failed', {\n surface,\n durationMs: timeoutMs,\n });\n onError?.({\n scope: 'infinite_scroll_timeout',\n message: 'Load more timed out',\n payload: {\n surface,\n durationMs: timeoutMs,\n },\n });\n onUiError?.('infinite_scroll_timeout', 'Load more timed out', {\n surface,\n durationMs: timeoutMs,\n });\n }, timeoutMs);\n\n startTransition(() => {\n runLoadMore((error) => {\n if (requestTokenRef.current !== requestToken) {\n return;\n }\n requestTokenRef.current = requestToken + 1;\n inFlightRef.current = false;\n clearPendingTimeout();\n const durationMs = Date.now() - startedAt;\n if (error != null) {\n setIncrementalError(error);\n onTelemetry?.('list_load_more_failed', {\n surface,\n durationMs,\n });\n onError?.({\n scope: 'infinite_scroll',\n message: error.message,\n payload: {\n surface,\n durationMs,\n },\n });\n onUiError?.('infinite_scroll', error.message, {\n surface,\n durationMs,\n });\n return;\n }\n onTelemetry?.('list_load_more_succeeded', {\n surface,\n durationMs,\n });\n });\n });\n }, [\n clearPendingTimeout,\n hasNext,\n isLoadingNext,\n nodes.length,\n onError,\n onTelemetry,\n onUiError,\n runLoadMore,\n surface,\n timeoutMs,\n ]);\n\n const retryLoadMore = useCallback(() => {\n loadMoreSafe();\n }, [loadMoreSafe]);\n\n return useMemo(() => {\n return {\n nodes,\n hasNext,\n isLoadingNext,\n incrementalError,\n loadMoreSafe,\n retryLoadMore,\n };\n }, [\n nodes,\n hasNext,\n isLoadingNext,\n incrementalError,\n loadMoreSafe,\n retryLoadMore,\n ]);\n};\n\nexport default useInfiniteConnection;\n"],"mappings":";;AA6DA,IAAa,KAAgC,EAC3C,UACA,YACA,kBACA,gBACA,aAAU,WACV,eAAY,MACZ,gBACA,cACA,iBAC4E;CAC5E,IAAM,CAAC,GAAkB,KAAuB,EAAuB,
|
|
1
|
+
{"version":3,"file":"useInfiniteConnection.js","names":[],"sources":["../../../src/hooks/useInfiniteConnection.ts"],"sourcesContent":["import {\n startTransition,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nexport type LoadMoreRunner = (\n onComplete: (error: Error | null) => void,\n) => void;\n\nexport type InfiniteConnectionTelemetryPayload = {\n surface: string;\n loadedCount?: number;\n durationMs?: number;\n};\n\nexport type InfiniteConnectionTelemetryEvent =\n | 'list_load_more_requested'\n | 'list_load_more_failed'\n | 'list_load_more_succeeded';\n\nexport type InfiniteConnectionErrorEvent = {\n scope: 'infinite_scroll' | 'infinite_scroll_timeout';\n message: string;\n payload: {\n surface: string;\n durationMs: number;\n };\n};\n\nexport type UseInfiniteConnectionParams<TNode> = {\n nodes: readonly TNode[];\n hasNext: boolean;\n isLoadingNext: boolean;\n runLoadMore: LoadMoreRunner;\n surface?: string;\n timeoutMs?: number;\n onTelemetry?: (\n event: InfiniteConnectionTelemetryEvent,\n payload: InfiniteConnectionTelemetryPayload,\n ) => void;\n onUiError?: (\n scope: InfiniteConnectionErrorEvent['scope'],\n message: string,\n payload: InfiniteConnectionErrorEvent['payload'],\n ) => void;\n onError?: (event: InfiniteConnectionErrorEvent) => void;\n};\n\nexport type UseInfiniteConnectionResult<TNode> = {\n nodes: readonly TNode[];\n hasNext: boolean;\n isLoadingNext: boolean;\n incrementalError: Error | null;\n loadMoreSafe: () => void;\n retryLoadMore: () => void;\n};\n\nexport const useInfiniteConnection = <TNode>({\n nodes,\n hasNext,\n isLoadingNext,\n runLoadMore,\n surface = 'unknown',\n timeoutMs = 15_000,\n onTelemetry,\n onUiError,\n onError,\n}: UseInfiniteConnectionParams<TNode>): UseInfiniteConnectionResult<TNode> => {\n const [incrementalError, setIncrementalError] = useState<Error | null>(null);\n const inFlightRef = useRef(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const requestTokenRef = useRef(0);\n\n const clearPendingTimeout = useCallback(() => {\n if (timeoutRef.current == null) {\n return;\n }\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }, []);\n\n useEffect(() => {\n return () => {\n clearPendingTimeout();\n };\n }, [clearPendingTimeout]);\n\n const loadMoreSafe = useCallback(() => {\n if (!hasNext || isLoadingNext || inFlightRef.current) {\n return;\n }\n inFlightRef.current = true;\n const requestToken = requestTokenRef.current + 1;\n requestTokenRef.current = requestToken;\n setIncrementalError(null);\n const startedAt = Date.now();\n onTelemetry?.('list_load_more_requested', {\n surface,\n loadedCount: nodes.length,\n });\n clearPendingTimeout();\n timeoutRef.current = setTimeout(() => {\n if (requestTokenRef.current !== requestToken) {\n return;\n }\n requestTokenRef.current = requestToken + 1;\n inFlightRef.current = false;\n setIncrementalError(new Error('timeout'));\n onTelemetry?.('list_load_more_failed', {\n surface,\n durationMs: timeoutMs,\n });\n onError?.({\n scope: 'infinite_scroll_timeout',\n message: 'Load more timed out',\n payload: {\n surface,\n durationMs: timeoutMs,\n },\n });\n onUiError?.('infinite_scroll_timeout', 'Load more timed out', {\n surface,\n durationMs: timeoutMs,\n });\n }, timeoutMs);\n\n startTransition(() => {\n runLoadMore((error) => {\n if (requestTokenRef.current !== requestToken) {\n return;\n }\n requestTokenRef.current = requestToken + 1;\n inFlightRef.current = false;\n clearPendingTimeout();\n const durationMs = Date.now() - startedAt;\n if (error != null) {\n setIncrementalError(error);\n onTelemetry?.('list_load_more_failed', {\n surface,\n durationMs,\n });\n onError?.({\n scope: 'infinite_scroll',\n message: error.message,\n payload: {\n surface,\n durationMs,\n },\n });\n onUiError?.('infinite_scroll', error.message, {\n surface,\n durationMs,\n });\n return;\n }\n onTelemetry?.('list_load_more_succeeded', {\n surface,\n durationMs,\n });\n });\n });\n }, [\n clearPendingTimeout,\n hasNext,\n isLoadingNext,\n nodes.length,\n onError,\n onTelemetry,\n onUiError,\n runLoadMore,\n surface,\n timeoutMs,\n ]);\n\n const retryLoadMore = useCallback(() => {\n loadMoreSafe();\n }, [loadMoreSafe]);\n\n return useMemo(() => {\n return {\n nodes,\n hasNext,\n isLoadingNext,\n incrementalError,\n loadMoreSafe,\n retryLoadMore,\n };\n }, [\n nodes,\n hasNext,\n isLoadingNext,\n incrementalError,\n loadMoreSafe,\n retryLoadMore,\n ]);\n};\n\nexport default useInfiniteConnection;\n"],"mappings":";;AA6DA,IAAa,KAAgC,EAC3C,UACA,YACA,kBACA,gBACA,aAAU,WACV,eAAY,MACZ,gBACA,cACA,iBAC4E;CAC5E,IAAM,CAAC,GAAkB,KAAuB,EAAuB,IAAI,GACrE,IAAc,EAAO,EAAK,GAC1B,IAAa,EAA6C,IAAI,GAC9D,IAAkB,EAAO,CAAC,GAE1B,IAAsB,QAAkB;EACxC,EAAW,WAAW,SAG1B,aAAa,EAAW,OAAO,GAC/B,EAAW,UAAU;CACvB,GAAG,CAAC,CAAC;CAEL,cACe;EACX,EAAoB;CACtB,GACC,CAAC,CAAmB,CAAC;CAExB,IAAM,IAAe,QAAkB;EACrC,IAAI,CAAC,KAAW,KAAiB,EAAY,SAC3C;EAEF,EAAY,UAAU;EACtB,IAAM,IAAe,EAAgB,UAAU;EAE/C,AADA,EAAgB,UAAU,GAC1B,EAAoB,IAAI;EACxB,IAAM,IAAY,KAAK,IAAI;EA+B3B,AA9BA,IAAc,4BAA4B;GACxC;GACA,aAAa,EAAM;EACrB,CAAC,GACD,EAAoB,GACpB,EAAW,UAAU,iBAAiB;GAChC,EAAgB,YAAY,MAGhC,EAAgB,UAAU,IAAe,GACzC,EAAY,UAAU,IACtB,EAAoB,gBAAI,MAAM,SAAS,CAAC,GACxC,IAAc,yBAAyB;IACrC;IACA,YAAY;GACd,CAAC,GACD,IAAU;IACR,OAAO;IACP,SAAS;IACT,SAAS;KACP;KACA,YAAY;IACd;GACF,CAAC,GACD,IAAY,2BAA2B,uBAAuB;IAC5D;IACA,YAAY;GACd,CAAC;EACH,GAAG,CAAS,GAEZ,QAAsB;GACpB,GAAa,MAAU;IACrB,IAAI,EAAgB,YAAY,GAC9B;IAIF,AAFA,EAAgB,UAAU,IAAe,GACzC,EAAY,UAAU,IACtB,EAAoB;IACpB,IAAM,IAAa,KAAK,IAAI,IAAI;IAChC,IAAI,KAAS,MAAM;KAcjB,AAbA,EAAoB,CAAK,GACzB,IAAc,yBAAyB;MACrC;MACA;KACF,CAAC,GACD,IAAU;MACR,OAAO;MACP,SAAS,EAAM;MACf,SAAS;OACP;OACA;MACF;KACF,CAAC,GACD,IAAY,mBAAmB,EAAM,SAAS;MAC5C;MACA;KACF,CAAC;KACD;IACF;IACA,IAAc,4BAA4B;KACxC;KACA;IACF,CAAC;GACH,CAAC;EACH,CAAC;CACH,GAAG;EACD;EACA;EACA;EACA,EAAM;EACN;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,GAEK,IAAgB,QAAkB;EACtC,EAAa;CACf,GAAG,CAAC,CAAY,CAAC;CAEjB,OAAO,SACE;EACL;EACA;EACA;EACA;EACA;EACA;CACF,IACC;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRefetchNeededReload.js","names":[],"sources":["../../../src/hooks/useRefetchNeededReload.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ntype RefetchReason = string;\n\ntype UseRefetchNeededReloadReturn = {\n reason: RefetchReason | null;\n onRefetchNeeded: (reason: RefetchReason | null | undefined) => void;\n reload: () => void;\n clear: () => void;\n};\n\n/** Track refetch-needed interruptions and expose a reload helper. */\nexport function useRefetchNeededReload(\n resetKey: string | null | undefined,\n): UseRefetchNeededReloadReturn {\n const [reason, setReason] = useState<RefetchReason | null>(null);\n\n useEffect(() => {\n setReason(null);\n }, [resetKey]);\n\n const onRefetchNeeded = useCallback(\n (nextReason: RefetchReason | null | undefined) => {\n setReason(nextReason ?? 'UNKNOWN');\n },\n [],\n );\n\n const reload = useCallback(() => {\n window.location.reload();\n }, []);\n\n const clear = useCallback(() => {\n setReason(null);\n }, []);\n\n return { reason, onRefetchNeeded, reload, clear };\n}\n"],"mappings":";;AAYA,SAAgB,EACd,GAC8B;CAC9B,IAAM,CAAC,GAAQ,KAAa,EAA+B,
|
|
1
|
+
{"version":3,"file":"useRefetchNeededReload.js","names":[],"sources":["../../../src/hooks/useRefetchNeededReload.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\n\ntype RefetchReason = string;\n\ntype UseRefetchNeededReloadReturn = {\n reason: RefetchReason | null;\n onRefetchNeeded: (reason: RefetchReason | null | undefined) => void;\n reload: () => void;\n clear: () => void;\n};\n\n/** Track refetch-needed interruptions and expose a reload helper. */\nexport function useRefetchNeededReload(\n resetKey: string | null | undefined,\n): UseRefetchNeededReloadReturn {\n const [reason, setReason] = useState<RefetchReason | null>(null);\n\n useEffect(() => {\n setReason(null);\n }, [resetKey]);\n\n const onRefetchNeeded = useCallback(\n (nextReason: RefetchReason | null | undefined) => {\n setReason(nextReason ?? 'UNKNOWN');\n },\n [],\n );\n\n const reload = useCallback(() => {\n window.location.reload();\n }, []);\n\n const clear = useCallback(() => {\n setReason(null);\n }, []);\n\n return { reason, onRefetchNeeded, reload, clear };\n}\n"],"mappings":";;AAYA,SAAgB,EACd,GAC8B;CAC9B,IAAM,CAAC,GAAQ,KAAa,EAA+B,IAAI;CAqB/D,OAnBA,QAAgB;EACd,EAAU,IAAI;CAChB,GAAG,CAAC,CAAQ,CAAC,GAiBN;EAAE;EAAQ,iBAfO,GACrB,MAAiD;GAChD,EAAU,KAAc,SAAS;EACnC,GACA,CAAC,CAWc;EAAiB,QARnB,QAAkB;GAC/B,OAAO,SAAS,OAAO;EACzB,GAAG,CAAC,CAM8B;EAAQ,OAJ5B,QAAkB;GAC9B,EAAU,IAAI;EAChB,GAAG,CAAC,CAEsC;CAAM;AAClD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSidebarGroupCollapse.js","names":[],"sources":["../../../src/hooks/useSidebarGroupCollapse.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type SidebarGroupCollapseState = Record<string, boolean | undefined>;\n\nexport type UseSidebarGroupCollapseInput = {\n groupIds: readonly string[];\n activeGroupId?: string | null;\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>;\n storageKey?: string;\n persist?: boolean;\n};\n\nconst readStoredState = (\n storageKey: string | undefined,\n): SidebarGroupCollapseState | null => {\n if (storageKey == null || typeof window === 'undefined') {\n return null;\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return null;\n }\n const parsed = JSON.parse(raw) as unknown;\n if (parsed == null || typeof parsed !== 'object') {\n return null;\n }\n const output: SidebarGroupCollapseState = {};\n Object.entries(parsed as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (typeof value === 'boolean') {\n output[key] = value;\n }\n },\n );\n return output;\n } catch {\n return null;\n }\n};\n\nconst buildInitialState = (\n groupIds: readonly string[],\n activeGroupId?: string | null,\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>,\n): SidebarGroupCollapseState => {\n const state: SidebarGroupCollapseState = {};\n groupIds.forEach((groupId) => {\n state[groupId] = defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n if (activeGroupId != null && groupIds.includes(activeGroupId)) {\n state[activeGroupId] = false;\n }\n return state;\n};\n\nexport const useSidebarGroupCollapse = (\n input: UseSidebarGroupCollapseInput,\n): {\n collapsedByGroupId: SidebarGroupCollapseState;\n setCollapsed: (groupId: string, collapsed: boolean) => void;\n} => {\n const {\n activeGroupId,\n defaultCollapsedByGroupId,\n groupIds,\n persist = false,\n storageKey,\n } = input;\n\n const groupIdList = useMemo(() => {\n return [...groupIds];\n }, [groupIds]);\n\n const [collapsedByGroupId, setCollapsedByGroupId] =\n useState<SidebarGroupCollapseState>(() => {\n if (persist) {\n const stored = readStoredState(storageKey);\n if (stored != null) {\n return {\n ...buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n ),\n ...stored,\n };\n }\n }\n return buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n );\n });\n\n useEffect(() => {\n setCollapsedByGroupId((prev) => {\n const next: SidebarGroupCollapseState = {};\n\n groupIdList.forEach((groupId) => {\n const existing = prev[groupId];\n next[groupId] =\n existing ?? defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n\n if (activeGroupId != null && groupIdList.includes(activeGroupId)) {\n next[activeGroupId] = false;\n }\n\n return next;\n });\n }, [activeGroupId, defaultCollapsedByGroupId, groupIdList]);\n\n useEffect(() => {\n if (!persist || storageKey == null || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify(collapsedByGroupId),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [collapsedByGroupId, persist, storageKey]);\n\n useEffect(() => {\n if (activeGroupId == null) {\n return;\n }\n setCollapsedByGroupId((prev) => {\n if (prev[activeGroupId] === false) {\n return prev;\n }\n return {\n ...prev,\n [activeGroupId]: false,\n };\n });\n }, [activeGroupId]);\n\n const setCollapsed = useCallback((groupId: string, collapsed: boolean) => {\n setCollapsedByGroupId((prev) => {\n if (prev[groupId] === collapsed) {\n return prev;\n }\n return {\n ...prev,\n [groupId]: collapsed,\n };\n });\n }, []);\n\n return {\n collapsedByGroupId,\n setCollapsed,\n };\n};\n\nexport default useSidebarGroupCollapse;\n"],"mappings":";;AAYA,IAAM,KACJ,MACqC;CACrC,IAAI,KAAc,QAAQ,OAAO,SAAW,KAC1C,OAAO;CAET,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,
|
|
1
|
+
{"version":3,"file":"useSidebarGroupCollapse.js","names":[],"sources":["../../../src/hooks/useSidebarGroupCollapse.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type SidebarGroupCollapseState = Record<string, boolean | undefined>;\n\nexport type UseSidebarGroupCollapseInput = {\n groupIds: readonly string[];\n activeGroupId?: string | null;\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>;\n storageKey?: string;\n persist?: boolean;\n};\n\nconst readStoredState = (\n storageKey: string | undefined,\n): SidebarGroupCollapseState | null => {\n if (storageKey == null || typeof window === 'undefined') {\n return null;\n }\n try {\n const raw = window.localStorage.getItem(storageKey);\n if (raw == null) {\n return null;\n }\n const parsed = JSON.parse(raw) as unknown;\n if (parsed == null || typeof parsed !== 'object') {\n return null;\n }\n const output: SidebarGroupCollapseState = {};\n Object.entries(parsed as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (typeof value === 'boolean') {\n output[key] = value;\n }\n },\n );\n return output;\n } catch {\n return null;\n }\n};\n\nconst buildInitialState = (\n groupIds: readonly string[],\n activeGroupId?: string | null,\n defaultCollapsedByGroupId?: Record<string, boolean | undefined>,\n): SidebarGroupCollapseState => {\n const state: SidebarGroupCollapseState = {};\n groupIds.forEach((groupId) => {\n state[groupId] = defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n if (activeGroupId != null && groupIds.includes(activeGroupId)) {\n state[activeGroupId] = false;\n }\n return state;\n};\n\nexport const useSidebarGroupCollapse = (\n input: UseSidebarGroupCollapseInput,\n): {\n collapsedByGroupId: SidebarGroupCollapseState;\n setCollapsed: (groupId: string, collapsed: boolean) => void;\n} => {\n const {\n activeGroupId,\n defaultCollapsedByGroupId,\n groupIds,\n persist = false,\n storageKey,\n } = input;\n\n const groupIdList = useMemo(() => {\n return [...groupIds];\n }, [groupIds]);\n\n const [collapsedByGroupId, setCollapsedByGroupId] =\n useState<SidebarGroupCollapseState>(() => {\n if (persist) {\n const stored = readStoredState(storageKey);\n if (stored != null) {\n return {\n ...buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n ),\n ...stored,\n };\n }\n }\n return buildInitialState(\n groupIdList,\n activeGroupId,\n defaultCollapsedByGroupId,\n );\n });\n\n useEffect(() => {\n setCollapsedByGroupId((prev) => {\n const next: SidebarGroupCollapseState = {};\n\n groupIdList.forEach((groupId) => {\n const existing = prev[groupId];\n next[groupId] =\n existing ?? defaultCollapsedByGroupId?.[groupId] ?? true;\n });\n\n if (activeGroupId != null && groupIdList.includes(activeGroupId)) {\n next[activeGroupId] = false;\n }\n\n return next;\n });\n }, [activeGroupId, defaultCollapsedByGroupId, groupIdList]);\n\n useEffect(() => {\n if (!persist || storageKey == null || typeof window === 'undefined') {\n return;\n }\n try {\n window.localStorage.setItem(\n storageKey,\n JSON.stringify(collapsedByGroupId),\n );\n } catch {\n // Ignore storage quota / privacy mode failures.\n }\n }, [collapsedByGroupId, persist, storageKey]);\n\n useEffect(() => {\n if (activeGroupId == null) {\n return;\n }\n setCollapsedByGroupId((prev) => {\n if (prev[activeGroupId] === false) {\n return prev;\n }\n return {\n ...prev,\n [activeGroupId]: false,\n };\n });\n }, [activeGroupId]);\n\n const setCollapsed = useCallback((groupId: string, collapsed: boolean) => {\n setCollapsedByGroupId((prev) => {\n if (prev[groupId] === collapsed) {\n return prev;\n }\n return {\n ...prev,\n [groupId]: collapsed,\n };\n });\n }, []);\n\n return {\n collapsedByGroupId,\n setCollapsed,\n };\n};\n\nexport default useSidebarGroupCollapse;\n"],"mappings":";;AAYA,IAAM,KACJ,MACqC;CACrC,IAAI,KAAc,QAAQ,OAAO,SAAW,KAC1C,OAAO;CAET,IAAI;EACF,IAAM,IAAM,OAAO,aAAa,QAAQ,CAAU;EAClD,IAAI,KAAO,MACT,OAAO;EAET,IAAM,IAAS,KAAK,MAAM,CAAG;EAC7B,IAAsB,OAAO,KAAW,aAApC,GACF,OAAO;EAET,IAAM,IAAoC,CAAC;EAQ3C,OAPA,OAAO,QAAQ,CAAiC,EAAE,SAC/C,CAAC,GAAK,OAAW;GAChB,AAAI,OAAO,KAAU,cACnB,EAAO,KAAO;EAElB,CACF,GACO;CACT,QAAQ;EACN,OAAO;CACT;AACF,GAEM,KACJ,GACA,GACA,MAC8B;CAC9B,IAAM,IAAmC,CAAC;CAO1C,OANA,EAAS,SAAS,MAAY;EAC5B,EAAM,KAAW,IAA4B,MAAY;CAC3D,CAAC,GACG,KAAiB,QAAQ,EAAS,SAAS,CAAa,MAC1D,EAAM,KAAiB,KAElB;AACT,GAEa,KACX,MAIG;CACH,IAAM,EACJ,kBACA,8BACA,aACA,aAAU,IACV,kBACE,GAEE,IAAc,QACX,CAAC,GAAG,CAAQ,GAClB,CAAC,CAAQ,CAAC,GAEP,CAAC,GAAoB,KACzB,QAA0C;EACxC,IAAI,GAAS;GACX,IAAM,IAAS,EAAgB,CAAU;GACzC,IAAI,KAAU,MACZ,OAAO;IACL,GAAG,EACD,GACA,GACA,CACF;IACA,GAAG;GACL;EAEJ;EACA,OAAO,EACL,GACA,GACA,CACF;CACF,CAAC;CA6DH,OA3DA,QAAgB;EACd,GAAuB,MAAS;GAC9B,IAAM,IAAkC,CAAC;GAYzC,OAVA,EAAY,SAAS,MAAY;IAE/B,EAAK,KADY,EAAK,MAER,IAA4B,MAAY;GACxD,CAAC,GAEG,KAAiB,QAAQ,EAAY,SAAS,CAAa,MAC7D,EAAK,KAAiB,KAGjB;EACT,CAAC;CACH,GAAG;EAAC;EAAe;EAA2B;CAAW,CAAC,GAE1D,QAAgB;EACV,OAAC,KAAW,KAAc,QAAQ,OAAO,SAAW,MAGxD,IAAI;GACF,OAAO,aAAa,QAClB,GACA,KAAK,UAAU,CAAkB,CACnC;EACF,QAAQ,CAER;CACF,GAAG;EAAC;EAAoB;EAAS;CAAU,CAAC,GAE5C,QAAgB;EACV,KAAiB,QAGrB,GAAuB,MACjB,EAAK,OAAmB,KACnB,IAEF;GACL,GAAG;IACF,IAAgB;EACnB,CACD;CACH,GAAG,CAAC,CAAa,CAAC,GAcX;EACL;EACA,cAdmB,GAAa,GAAiB,MAAuB;GACxE,GAAuB,MACjB,EAAK,OAAa,IACb,IAEF;IACL,GAAG;KACF,IAAU;GACb,CACD;EACH,GAAG,CAAC,CAIF;CACF;AACF"}
|