@stackcraftmx/calcita 0.0.0-stage → 0.25.0
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/LICENSE +110 -0
- package/README.md +700 -2
- package/cli/askQuestions.js +63 -0
- package/cli/calcita.js +150 -0
- package/cli/makeComponent.js +50 -0
- package/cli/makeForm.js +68 -0
- package/cli/makeModule.js +78 -0
- package/cli/makePage.js +62 -0
- package/cli/names.js +64 -0
- package/cli/newProject.js +103 -0
- package/cli/packageVersions.js +38 -0
- package/cli/projectAnswers.js +145 -0
- package/cli/projectConfig.js +38 -0
- package/cli/projectFiles.js +128 -0
- package/cli/screenLabels.js +41 -0
- package/cli/templateFiles.js +186 -0
- package/cli/templates/component/core/__ComponentName__.jsx.tpl +23 -0
- package/cli/templates/component/module/__ComponentName__.jsx.tpl +21 -0
- package/cli/templates/form/formik/__FormName__.jsx.tpl +50 -0
- package/cli/templates/form/hookForm/__FormName__.jsx.tpl +53 -0
- package/cli/templates/form/shared/__formName__Schema.js.tpl +20 -0
- package/cli/templates/form/shared/__formName__Texts.js.tpl +6 -0
- package/cli/templates/module/__Name__Page.jsx.tpl +75 -0
- package/cli/templates/module/__name__Api.js.tpl +39 -0
- package/cli/templates/module/__name__Texts.js.tpl +27 -0
- package/cli/templates/module/menu.js.tpl +21 -0
- package/cli/templates/module/routes.js.tpl +7 -0
- package/cli/templates/moduleServer/__name__Server.js.tpl +68 -0
- package/cli/templates/page/__PageName__Page.jsx.tpl +22 -0
- package/cli/templates/page/__pageName__PageTexts.js.tpl +23 -0
- package/cli/templates/project/README.md.tpl +83 -0
- package/cli/templates/project/dot-gitignore.tpl +11 -0
- package/cli/templates/project/index.html.tpl +20 -0
- package/cli/templates/project/jsconfig.json.tpl +16 -0
- package/cli/templates/project/pnpm-workspace.yaml.tpl +5 -0
- package/cli/templates/project/public/favicon.svg +1 -0
- package/cli/templates/project/public/icons/apple-touch-icon.png +0 -0
- package/cli/templates/project/public/icons/icon-192.png +0 -0
- package/cli/templates/project/public/icons/icon-512-maskable.png +0 -0
- package/cli/templates/project/public/icons/icon-512.png +0 -0
- package/cli/templates/project/public/manifest.webmanifest.tpl +17 -0
- package/cli/templates/project/src/app/AppProviders.jsx.tpl +107 -0
- package/cli/templates/project/src/app/AppShell.jsx.tpl +87 -0
- package/cli/templates/project/src/app/appRouter.jsx.tpl +51 -0
- package/cli/templates/project/src/app/appSettings.js.tpl +27 -0
- package/cli/templates/project/src/app/appTexts.js.tpl +15 -0
- package/cli/templates/project/src/app/combineTexts.js.tpl +31 -0
- package/cli/templates/project/src/app/i18n.js.tpl +19 -0
- package/cli/templates/project/src/app/shellTexts.js.tpl +16 -0
- package/cli/templates/project/src/core/AppLogo.jsx.tpl +14 -0
- package/cli/templates/project/src/core/accountConnector.js.tpl +36 -0
- package/cli/templates/project/src/core/apiClient.js.tpl +15 -0
- package/cli/templates/project/src/core/appPaths.js.tpl +11 -0
- package/cli/templates/project/src/core/index.js.tpl +9 -0
- package/cli/templates/project/src/core/publicPaths.js.tpl +24 -0
- package/cli/templates/project/src/fakeServer/networkDelay.js.tpl +40 -0
- package/cli/templates/project/src/fakeServer/serverText.js.tpl +20 -0
- package/cli/templates/project/src/main.jsx.tpl +24 -0
- package/cli/templates/project/src/modules/auth/ForgotPasswordPage.jsx.tpl +14 -0
- package/cli/templates/project/src/modules/auth/ResetPasswordPage.jsx.tpl +15 -0
- package/cli/templates/project/src/modules/auth/SignInPage.jsx.tpl +29 -0
- package/cli/templates/project/src/modules/auth/authTexts.js.tpl +6 -0
- package/cli/templates/project/src/modules/auth/routes.js.tpl +11 -0
- package/cli/templates/project/src/modules/home/HomePage.jsx.tpl +38 -0
- package/cli/templates/project/src/modules/home/homeTexts.js.tpl +29 -0
- package/cli/templates/project/src/modules/home/menu.js.tpl +17 -0
- package/cli/templates/project/src/modules/home/routes.js.tpl +4 -0
- package/cli/templates/project/src/modules/profile/ProfilePage.jsx.tpl +13 -0
- package/cli/templates/project/src/modules/profile/routes.js.tpl +6 -0
- package/cli/templates/project/vite.config.js.tpl +53 -0
- package/dist/DataTable/AuditTrailDialog.js +40 -0
- package/dist/DataTable/AuditTrailDialog.js.map +1 -0
- package/dist/DataTable/AuditTrailTable.js +89 -0
- package/dist/DataTable/AuditTrailTable.js.map +1 -0
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +71 -0
- package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -0
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +51 -0
- package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -0
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +54 -0
- package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -0
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js +24 -0
- package/dist/DataTable/ColumnFilters/TextColumnFilter.js.map +1 -0
- package/dist/DataTable/EmptyState.js +22 -0
- package/dist/DataTable/EmptyState.js.map +1 -0
- package/dist/DataTable/FilterChips.js +39 -0
- package/dist/DataTable/FilterChips.js.map +1 -0
- package/dist/DataTable/GoToPage.js +63 -0
- package/dist/DataTable/GoToPage.js.map +1 -0
- package/dist/DataTable/ServerTable.js +477 -0
- package/dist/DataTable/ServerTable.js.map +1 -0
- package/dist/DataTable/buildChipConfig.js +27 -0
- package/dist/DataTable/buildChipConfig.js.map +1 -0
- package/dist/DataTable/columns.js +122 -0
- package/dist/DataTable/columns.js.map +1 -0
- package/dist/DataTable/filterContext.js +15 -0
- package/dist/DataTable/filterContext.js.map +1 -0
- package/dist/DataTable/rowSelection.js +61 -0
- package/dist/DataTable/rowSelection.js.map +1 -0
- package/dist/DataTable/serverTableParams.js +19 -0
- package/dist/DataTable/serverTableParams.js.map +1 -0
- package/dist/DataTable/tableMachine.js +87 -0
- package/dist/DataTable/tableMachine.js.map +1 -0
- package/dist/DataTable/useDebouncedFilter.js +29 -0
- package/dist/DataTable/useDebouncedFilter.js.map +1 -0
- package/dist/DataTable/useTableState.js +132 -0
- package/dist/DataTable/useTableState.js.map +1 -0
- package/dist/access/Can.js +9 -0
- package/dist/access/Can.js.map +1 -0
- package/dist/access/PermissionMatrix.js +84 -0
- package/dist/access/PermissionMatrix.js.map +1 -0
- package/dist/access/RequireAccess.js +14 -0
- package/dist/access/RequireAccess.js.map +1 -0
- package/dist/access/accessRules.js +49 -0
- package/dist/access/accessRules.js.map +1 -0
- package/dist/access/permissionGroups.js +43 -0
- package/dist/access/permissionGroups.js.map +1 -0
- package/dist/access/useCan.js +12 -0
- package/dist/access/useCan.js.map +1 -0
- package/dist/account/AccountProvider.js +58 -0
- package/dist/account/AccountProvider.js.map +1 -0
- package/dist/account/AccountSecuritySection.js +81 -0
- package/dist/account/AccountSecuritySection.js.map +1 -0
- package/dist/account/DemoTotpCodeButton.js +26 -0
- package/dist/account/DemoTotpCodeButton.js.map +1 -0
- package/dist/account/ForgotPasswordScreen.js +27 -0
- package/dist/account/ForgotPasswordScreen.js.map +1 -0
- package/dist/account/ProfileScreen.js +134 -0
- package/dist/account/ProfileScreen.js.map +1 -0
- package/dist/account/ResetPasswordScreen.js +58 -0
- package/dist/account/ResetPasswordScreen.js.map +1 -0
- package/dist/account/SignInScreen.js +102 -0
- package/dist/account/SignInScreen.js.map +1 -0
- package/dist/account/accountConnector.js +31 -0
- package/dist/account/accountConnector.js.map +1 -0
- package/dist/account/demo/createDemoAccountConnector.js +368 -0
- package/dist/account/demo/createDemoAccountConnector.js.map +1 -0
- package/dist/account/demo/totp.js +61 -0
- package/dist/account/demo/totp.js.map +1 -0
- package/dist/account/restAccountConnector.js +118 -0
- package/dist/account/restAccountConnector.js.map +1 -0
- package/dist/account-demo.js +12 -0
- package/dist/account-demo.js.map +1 -0
- package/dist/account.js +25 -0
- package/dist/account.js.map +1 -0
- package/dist/adapters/i18next.js +7 -0
- package/dist/adapters/i18next.js.map +1 -0
- package/dist/adapters/nextNavigation.js +36 -0
- package/dist/adapters/nextNavigation.js.map +1 -0
- package/dist/adapters/reactRouter.js +7 -0
- package/dist/adapters/reactRouter.js.map +1 -0
- package/dist/adapters/reactRouterRoutes.js +49 -0
- package/dist/adapters/reactRouterRoutes.js.map +1 -0
- package/dist/api/ApiError.js +58 -0
- package/dist/api/ApiError.js.map +1 -0
- package/dist/api/createApiClient.js +256 -0
- package/dist/api/createApiClient.js.map +1 -0
- package/dist/api/staleChunks.js +47 -0
- package/dist/api/staleChunks.js.map +1 -0
- package/dist/appShell/AccountMenu.js +86 -0
- package/dist/appShell/AccountMenu.js.map +1 -0
- package/dist/appShell/AppLayout.js +513 -0
- package/dist/appShell/AppLayout.js.map +1 -0
- package/dist/appShell/AppearanceSettings.js +116 -0
- package/dist/appShell/AppearanceSettings.js.map +1 -0
- package/dist/appShell/AuthLayout.js +46 -0
- package/dist/appShell/AuthLayout.js.map +1 -0
- package/dist/appShell/BarActionButton.js +31 -0
- package/dist/appShell/BarActionButton.js.map +1 -0
- package/dist/appShell/BarActions.js +105 -0
- package/dist/appShell/BarActions.js.map +1 -0
- package/dist/appShell/BarCapsule.js +50 -0
- package/dist/appShell/BarCapsule.js.map +1 -0
- package/dist/appShell/BarSearch.js +92 -0
- package/dist/appShell/BarSearch.js.map +1 -0
- package/dist/appShell/HeaderTools.js +53 -0
- package/dist/appShell/HeaderTools.js.map +1 -0
- package/dist/appShell/MobileTabBar.js +348 -0
- package/dist/appShell/MobileTabBar.js.map +1 -0
- package/dist/appShell/SettingsMenu.js +41 -0
- package/dist/appShell/SettingsMenu.js.map +1 -0
- package/dist/appShell/SideMenu.js +217 -0
- package/dist/appShell/SideMenu.js.map +1 -0
- package/dist/appShell/SideMenuEntry.js +140 -0
- package/dist/appShell/SideMenuEntry.js.map +1 -0
- package/dist/appShell/SubmenuActionsMenu.js +71 -0
- package/dist/appShell/SubmenuActionsMenu.js.map +1 -0
- package/dist/appShell/TabBarEditor.js +55 -0
- package/dist/appShell/TabBarEditor.js.map +1 -0
- package/dist/appShell/TopMenu.js +80 -0
- package/dist/appShell/TopMenu.js.map +1 -0
- package/dist/appShell/appMenuContext.js +11 -0
- package/dist/appShell/appMenuContext.js.map +1 -0
- package/dist/appShell/barActionsSlot.js +26 -0
- package/dist/appShell/barActionsSlot.js.map +1 -0
- package/dist/appShell/barMenuPlacement.js +33 -0
- package/dist/appShell/barMenuPlacement.js.map +1 -0
- package/dist/appShell/menuItemText.js +33 -0
- package/dist/appShell/menuItemText.js.map +1 -0
- package/dist/appShell/pageTitle.js +45 -0
- package/dist/appShell/pageTitle.js.map +1 -0
- package/dist/appShell/shellSizes.js +40 -0
- package/dist/appShell/shellSizes.js.map +1 -0
- package/dist/appShell/tabBarRule.js +12 -0
- package/dist/appShell/tabBarRule.js.map +1 -0
- package/dist/appShell/tabBarScroll.js +23 -0
- package/dist/appShell/tabBarScroll.js.map +1 -0
- package/dist/appShell/useDrawerCollapsed.js +29 -0
- package/dist/appShell/useDrawerCollapsed.js.map +1 -0
- package/dist/appShell/useFittingActionCount.js +45 -0
- package/dist/appShell/useFittingActionCount.js.map +1 -0
- package/dist/appShell/usePinnedMobileTabs.js +32 -0
- package/dist/appShell/usePinnedMobileTabs.js.map +1 -0
- package/dist/appShell/useTabBarMinimized.js +33 -0
- package/dist/appShell/useTabBarMinimized.js.map +1 -0
- package/dist/auth/PasswordChecklist.js +44 -0
- package/dist/auth/PasswordChecklist.js.map +1 -0
- package/dist/auth/passwordRules.js +43 -0
- package/dist/auth/passwordRules.js.map +1 -0
- package/dist/calendar/EventCalendar.js +149 -0
- package/dist/calendar/EventCalendar.js.map +1 -0
- package/dist/calendar/EventDetails.js +74 -0
- package/dist/calendar/EventDetails.js.map +1 -0
- package/dist/calendar/calendarEvents.js +31 -0
- package/dist/calendar/calendarEvents.js.map +1 -0
- package/dist/calendar.js +13 -0
- package/dist/calendar.js.map +1 -0
- package/dist/charts.js +16 -0
- package/dist/charts.js.map +1 -0
- package/dist/date-pickers.js +8 -0
- package/dist/date-pickers.js.map +1 -0
- package/dist/datePickers/DateInput.js +76 -0
- package/dist/datePickers/DateInput.js.map +1 -0
- package/dist/datePickers/FormDateField.js +12 -0
- package/dist/datePickers/FormDateField.js.map +1 -0
- package/dist/dates.js +25 -0
- package/dist/dates.js.map +1 -0
- package/dist/dictionaries/dictionaries.js +48 -0
- package/dist/dictionaries/dictionaries.js.map +1 -0
- package/dist/downloads/DownloadManager.js +195 -0
- package/dist/downloads/DownloadManager.js.map +1 -0
- package/dist/downloads/downloadQueue.js +56 -0
- package/dist/downloads/downloadQueue.js.map +1 -0
- package/dist/downloads/downloadsMachine.js +80 -0
- package/dist/downloads/downloadsMachine.js.map +1 -0
- package/dist/downloads/fileTypes.js +22 -0
- package/dist/downloads/fileTypes.js.map +1 -0
- package/dist/excel/reportWorkbook.js +299 -0
- package/dist/excel/reportWorkbook.js.map +1 -0
- package/dist/excel.js +13 -0
- package/dist/excel.js.map +1 -0
- package/dist/feedback/ConfirmDialog.js +73 -0
- package/dist/feedback/ConfirmDialog.js.map +1 -0
- package/dist/feedback/ModalWaiting.js +23 -0
- package/dist/feedback/ModalWaiting.js.map +1 -0
- package/dist/feedback/NewBuildNotice.js +79 -0
- package/dist/feedback/NewBuildNotice.js.map +1 -0
- package/dist/feedback/StaleBuildBoundary.js +36 -0
- package/dist/feedback/StaleBuildBoundary.js.map +1 -0
- package/dist/feedback/Toaster.js +20 -0
- package/dist/feedback/Toaster.js.map +1 -0
- package/dist/feedback/confirmActionMachine.js +67 -0
- package/dist/feedback/confirmActionMachine.js.map +1 -0
- package/dist/feedback/toast.js +88 -0
- package/dist/feedback/toast.js.map +1 -0
- package/dist/feedback/useConfirmAction.js +40 -0
- package/dist/feedback/useConfirmAction.js.map +1 -0
- package/dist/filepond/FileDropzone.js +256 -0
- package/dist/filepond/FileDropzone.js.map +1 -0
- package/dist/filepond/pondServer.js +48 -0
- package/dist/filepond/pondServer.js.map +1 -0
- package/dist/filepond.js +10 -0
- package/dist/filepond.js.map +1 -0
- package/dist/files.js +43 -0
- package/dist/files.js.map +1 -0
- package/dist/formatting.js +205 -0
- package/dist/formatting.js.map +1 -0
- package/dist/forms/FormCatalogField.js +12 -0
- package/dist/forms/FormCatalogField.js.map +1 -0
- package/dist/forms/FormColorField.js +12 -0
- package/dist/forms/FormColorField.js.map +1 -0
- package/dist/forms/FormNumberField.js +12 -0
- package/dist/forms/FormNumberField.js.map +1 -0
- package/dist/forms/FormProblemAlert.js +15 -0
- package/dist/forms/FormProblemAlert.js.map +1 -0
- package/dist/forms/FormSelectField.js +12 -0
- package/dist/forms/FormSelectField.js.map +1 -0
- package/dist/forms/FormServerProblem.js +23 -0
- package/dist/forms/FormServerProblem.js.map +1 -0
- package/dist/forms/FormTextField.js +12 -0
- package/dist/forms/FormTextField.js.map +1 -0
- package/dist/forms/FormWizard.js +63 -0
- package/dist/forms/FormWizard.js.map +1 -0
- package/dist/forms/SubmitButton.js +14 -0
- package/dist/forms/SubmitButton.js.map +1 -0
- package/dist/forms/applyServerProblem.js +15 -0
- package/dist/forms/applyServerProblem.js.map +1 -0
- package/dist/forms/auth/ChangePasswordForm.js +47 -0
- package/dist/forms/auth/ChangePasswordForm.js.map +1 -0
- package/dist/forms/auth/ForgotPasswordForm.js +50 -0
- package/dist/forms/auth/ForgotPasswordForm.js.map +1 -0
- package/dist/forms/auth/SignInForm.js +48 -0
- package/dist/forms/auth/SignInForm.js.map +1 -0
- package/dist/forms/security/SecondStepForm.js +122 -0
- package/dist/forms/security/SecondStepForm.js.map +1 -0
- package/dist/forms/security/TwoStepVerificationCard.js +338 -0
- package/dist/forms/security/TwoStepVerificationCard.js.map +1 -0
- package/dist/forms/security/securityRules.js +28 -0
- package/dist/forms/security/securityRules.js.map +1 -0
- package/dist/forms/serverProblemFields.js +25 -0
- package/dist/forms/serverProblemFields.js.map +1 -0
- package/dist/forms/useFormikField.js +16 -0
- package/dist/forms/useFormikField.js.map +1 -0
- package/dist/forms/validation.js +55 -0
- package/dist/forms/validation.js.map +1 -0
- package/dist/forms/validationMessages.js +16 -0
- package/dist/forms/validationMessages.js.map +1 -0
- package/dist/forms.js +57 -0
- package/dist/forms.js.map +1 -0
- package/dist/hookForm/FormCatalogField.js +12 -0
- package/dist/hookForm/FormCatalogField.js.map +1 -0
- package/dist/hookForm/FormColorField.js +12 -0
- package/dist/hookForm/FormColorField.js.map +1 -0
- package/dist/hookForm/FormNumberField.js +12 -0
- package/dist/hookForm/FormNumberField.js.map +1 -0
- package/dist/hookForm/FormProblemAlert.js +17 -0
- package/dist/hookForm/FormProblemAlert.js.map +1 -0
- package/dist/hookForm/FormSelectField.js +12 -0
- package/dist/hookForm/FormSelectField.js.map +1 -0
- package/dist/hookForm/FormTextField.js +12 -0
- package/dist/hookForm/FormTextField.js.map +1 -0
- package/dist/hookForm/FormWizard.js +59 -0
- package/dist/hookForm/FormWizard.js.map +1 -0
- package/dist/hookForm/SubmitButton.js +15 -0
- package/dist/hookForm/SubmitButton.js.map +1 -0
- package/dist/hookForm/applyServerProblem.js +21 -0
- package/dist/hookForm/applyServerProblem.js.map +1 -0
- package/dist/hookForm/useHookFormField.js +19 -0
- package/dist/hookForm/useHookFormField.js.map +1 -0
- package/dist/i18next.js +5 -0
- package/dist/i18next.js.map +1 -0
- package/dist/identifiers.js +8 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/inbox/InboxLayout.js +104 -0
- package/dist/inbox/InboxLayout.js.map +1 -0
- package/dist/inbox/MessageList.js +114 -0
- package/dist/inbox/MessageList.js.map +1 -0
- package/dist/inbox/MessageView.js +104 -0
- package/dist/inbox/MessageView.js.map +1 -0
- package/dist/inbox/inboxDates.js +9 -0
- package/dist/inbox/inboxDates.js.map +1 -0
- package/dist/index.js +407 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/CatalogInput.js +66 -0
- package/dist/inputs/CatalogInput.js.map +1 -0
- package/dist/inputs/ColorInput.js +109 -0
- package/dist/inputs/ColorInput.js.map +1 -0
- package/dist/inputs/FieldFrame.js +20 -0
- package/dist/inputs/FieldFrame.js.map +1 -0
- package/dist/inputs/FormSection.js +105 -0
- package/dist/inputs/FormSection.js.map +1 -0
- package/dist/inputs/NumberInput.js +70 -0
- package/dist/inputs/NumberInput.js.map +1 -0
- package/dist/inputs/SelectInput.js +84 -0
- package/dist/inputs/SelectInput.js.map +1 -0
- package/dist/inputs/TextInput.js +101 -0
- package/dist/inputs/TextInput.js.map +1 -0
- package/dist/inputs/WizardLayout.js +54 -0
- package/dist/inputs/WizardLayout.js.map +1 -0
- package/dist/inputs/colorContrast.js +46 -0
- package/dist/inputs/colorContrast.js.map +1 -0
- package/dist/inputs/formLayoutContext.js +9 -0
- package/dist/inputs/formLayoutContext.js.map +1 -0
- package/dist/inputs/numberText.js +48 -0
- package/dist/inputs/numberText.js.map +1 -0
- package/dist/kanban/KanbanBoard.js +338 -0
- package/dist/kanban/KanbanBoard.js.map +1 -0
- package/dist/kanban/kanbanCards.js +19 -0
- package/dist/kanban/kanbanCards.js.map +1 -0
- package/dist/kanban/kanbanMoves.js +29 -0
- package/dist/kanban/kanbanMoves.js.map +1 -0
- package/dist/kanban.js +15 -0
- package/dist/kanban.js.map +1 -0
- package/dist/laravel/csrfRetry.js +18 -0
- package/dist/laravel/csrfRetry.js.map +1 -0
- package/dist/laravel.js +6 -0
- package/dist/laravel.js.map +1 -0
- package/dist/lastListUrl.js +35 -0
- package/dist/lastListUrl.js.map +1 -0
- package/dist/locales/en.js +787 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/es.js +787 -0
- package/dist/locales/es.js.map +1 -0
- package/dist/maps/MapView.js +116 -0
- package/dist/maps/MapView.js.map +1 -0
- package/dist/maps/mapMarkers.js +19 -0
- package/dist/maps/mapMarkers.js.map +1 -0
- package/dist/maps.js +10 -0
- package/dist/maps.js.map +1 -0
- package/dist/money/money.js +380 -0
- package/dist/money/money.js.map +1 -0
- package/dist/money.js +6 -0
- package/dist/money.js.map +1 -0
- package/dist/navigation/appMenu.js +93 -0
- package/dist/navigation/appMenu.js.map +1 -0
- package/dist/navigation/useMenuBadges.js +45 -0
- package/dist/navigation/useMenuBadges.js.map +1 -0
- package/dist/navigation.js +30 -0
- package/dist/navigation.js.map +1 -0
- package/dist/navigationTrail.js +82 -0
- package/dist/navigationTrail.js.map +1 -0
- package/dist/next.js +5 -0
- package/dist/next.js.map +1 -0
- package/dist/observability/buildWatch.js +19 -0
- package/dist/observability/buildWatch.js.map +1 -0
- package/dist/observability/logger.js +43 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/publishedBuild.js +39 -0
- package/dist/observability/publishedBuild.js.map +1 -0
- package/dist/observability/usePublishedBuildWatch.js +77 -0
- package/dist/observability/usePublishedBuildWatch.js.map +1 -0
- package/dist/passkeys.js +7 -0
- package/dist/passkeys.js.map +1 -0
- package/dist/periodRanges.js +33 -0
- package/dist/periodRanges.js.map +1 -0
- package/dist/problems.js +51 -0
- package/dist/problems.js.map +1 -0
- package/dist/pwa/InstallAppSetting.js +34 -0
- package/dist/pwa/InstallAppSetting.js.map +1 -0
- package/dist/pwa/InstallInstructionsDialog.js +35 -0
- package/dist/pwa/InstallInstructionsDialog.js.map +1 -0
- package/dist/pwa/InstallPromptBanner.js +70 -0
- package/dist/pwa/InstallPromptBanner.js.map +1 -0
- package/dist/pwa/installInstructions.js +60 -0
- package/dist/pwa/installInstructions.js.map +1 -0
- package/dist/pwa/useInstallPrompt.js +71 -0
- package/dist/pwa/useInstallPrompt.js.map +1 -0
- package/dist/react-hook-form.js +32 -0
- package/dist/react-hook-form.js.map +1 -0
- package/dist/react-router.js +10 -0
- package/dist/react-router.js.map +1 -0
- package/dist/security/ActivityLog.js +80 -0
- package/dist/security/ActivityLog.js.map +1 -0
- package/dist/security/RecoveryCodesDialog.js +85 -0
- package/dist/security/RecoveryCodesDialog.js.map +1 -0
- package/dist/security/SessionsCard.js +83 -0
- package/dist/security/SessionsCard.js.map +1 -0
- package/dist/security/passkeys.js +39 -0
- package/dist/security/passkeys.js.map +1 -0
- package/dist/table.js +37 -0
- package/dist/table.js.map +1 -0
- package/dist/theme/androidDevice.js +16 -0
- package/dist/theme/androidDevice.js.map +1 -0
- package/dist/theme/appleTracking.js +34 -0
- package/dist/theme/appleTracking.js.map +1 -0
- package/dist/theme/components/MuiAppBar.js +27 -0
- package/dist/theme/components/MuiAppBar.js.map +1 -0
- package/dist/theme/components/MuiBackdrop.js +13 -0
- package/dist/theme/components/MuiBackdrop.js.map +1 -0
- package/dist/theme/components/MuiButton.js +25 -0
- package/dist/theme/components/MuiButton.js.map +1 -0
- package/dist/theme/components/MuiButtonBase.js +16 -0
- package/dist/theme/components/MuiButtonBase.js.map +1 -0
- package/dist/theme/components/MuiChip.js +30 -0
- package/dist/theme/components/MuiChip.js.map +1 -0
- package/dist/theme/components/MuiDataGrid.js +30 -0
- package/dist/theme/components/MuiDataGrid.js.map +1 -0
- package/dist/theme/components/MuiDialog.js +13 -0
- package/dist/theme/components/MuiDialog.js.map +1 -0
- package/dist/theme/components/MuiDrawer.js +18 -0
- package/dist/theme/components/MuiDrawer.js.map +1 -0
- package/dist/theme/components/MuiMenuItem.js +17 -0
- package/dist/theme/components/MuiMenuItem.js.map +1 -0
- package/dist/theme/components/MuiTypography.js +22 -0
- package/dist/theme/components/MuiTypography.js.map +1 -0
- package/dist/theme/components/glassComponents.js +885 -0
- package/dist/theme/components/glassComponents.js.map +1 -0
- package/dist/theme/components/minimalComponents.js +146 -0
- package/dist/theme/components/minimalComponents.js.map +1 -0
- package/dist/theme/components/paletteOf.js +7 -0
- package/dist/theme/components/paletteOf.js.map +1 -0
- package/dist/theme/createToolkitTheme.js +100 -0
- package/dist/theme/createToolkitTheme.js.map +1 -0
- package/dist/theme/glassSurface.js +328 -0
- package/dist/theme/glassSurface.js.map +1 -0
- package/dist/theme/glassToasterStyles.js +50 -0
- package/dist/theme/glassToasterStyles.js.map +1 -0
- package/dist/theme/mergeComponents.js +42 -0
- package/dist/theme/mergeComponents.js.map +1 -0
- package/dist/theme/stackcraftPalette.js +59 -0
- package/dist/theme/stackcraftPalette.js.map +1 -0
- package/dist/theme/toolkitComponents.js +28 -0
- package/dist/theme/toolkitComponents.js.map +1 -0
- package/dist/timeline.js +8 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toolkit/ComponentTexts.js +13 -0
- package/dist/toolkit/ComponentTexts.js.map +1 -0
- package/dist/toolkit/ToolkitProvider.js +57 -0
- package/dist/toolkit/ToolkitProvider.js.map +1 -0
- package/dist/toolkit/browserNavigation.js +33 -0
- package/dist/toolkit/browserNavigation.js.map +1 -0
- package/dist/toolkit/componentTextsContext.js +15 -0
- package/dist/toolkit/componentTextsContext.js.map +1 -0
- package/dist/toolkit/hashNavigation.js +40 -0
- package/dist/toolkit/hashNavigation.js.map +1 -0
- package/dist/toolkit/navigationPaths.js +49 -0
- package/dist/toolkit/navigationPaths.js.map +1 -0
- package/dist/toolkit/toolkitContext.js +19 -0
- package/dist/toolkit/toolkitContext.js.map +1 -0
- package/dist/toolkit/toolkitSettings.js +107 -0
- package/dist/toolkit/toolkitSettings.js.map +1 -0
- package/dist/toolkit/useFormatters.js +12 -0
- package/dist/toolkit/useFormatters.js.map +1 -0
- package/dist/toolkit/useToolkitTranslation.js +22 -0
- package/dist/toolkit/useToolkitTranslation.js.map +1 -0
- package/dist/types/DataTable/AuditTrailDialog.d.ts +32 -0
- package/dist/types/DataTable/AuditTrailTable.d.ts +30 -0
- package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +8 -0
- package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +16 -0
- package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +26 -0
- package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +8 -0
- package/dist/types/DataTable/ColumnFilters/index.d.ts +4 -0
- package/dist/types/DataTable/EmptyState.d.ts +13 -0
- package/dist/types/DataTable/FilterChips.d.ts +17 -0
- package/dist/types/DataTable/GoToPage.d.ts +13 -0
- package/dist/types/DataTable/SelectionBar.d.ts +32 -0
- package/dist/types/DataTable/ServerTable.d.ts +171 -0
- package/dist/types/DataTable/buildChipConfig.d.ts +22 -0
- package/dist/types/DataTable/columns.d.ts +93 -0
- package/dist/types/DataTable/filterContext.d.ts +13 -0
- package/dist/types/DataTable/index.d.ts +13 -0
- package/dist/types/DataTable/rowSelection.d.ts +113 -0
- package/dist/types/DataTable/serverTableParams.d.ts +16 -0
- package/dist/types/DataTable/tableMachine.d.ts +41 -0
- package/dist/types/DataTable/useDebouncedFilter.d.ts +8 -0
- package/dist/types/DataTable/useTableState.d.ts +93 -0
- package/dist/types/access/Can.d.ts +11 -0
- package/dist/types/access/PermissionMatrix.d.ts +23 -0
- package/dist/types/access/RequireAccess.d.ts +11 -0
- package/dist/types/access/accessRules.d.ts +24 -0
- package/dist/types/access/permissionGroups.d.ts +56 -0
- package/dist/types/access/useCan.d.ts +11 -0
- package/dist/types/account/AccountProvider.d.ts +27 -0
- package/dist/types/account/AccountSecuritySection.d.ts +9 -0
- package/dist/types/account/DemoTotpCodeButton.d.ts +6 -0
- package/dist/types/account/ForgotPasswordScreen.d.ts +17 -0
- package/dist/types/account/ProfileScreen.d.ts +43 -0
- package/dist/types/account/ResetPasswordScreen.d.ts +21 -0
- package/dist/types/account/SignInScreen.d.ts +27 -0
- package/dist/types/account/accountConnector.d.ts +268 -0
- package/dist/types/account/demo/createDemoAccountConnector.d.ts +30 -0
- package/dist/types/account/demo/totp.d.ts +45 -0
- package/dist/types/account/restAccountConnector.d.ts +49 -0
- package/dist/types/account-demo.d.ts +2 -0
- package/dist/types/account.d.ts +16 -0
- package/dist/types/adapters/i18next.d.ts +11 -0
- package/dist/types/adapters/nextNavigation.d.ts +33 -0
- package/dist/types/adapters/reactRouter.d.ts +6 -0
- package/dist/types/adapters/reactRouterRoutes.d.ts +42 -0
- package/dist/types/api/ApiError.d.ts +42 -0
- package/dist/types/api/createApiClient.d.ts +174 -0
- package/dist/types/api/staleChunks.d.ts +15 -0
- package/dist/types/appShell/AccountMenu.d.ts +28 -0
- package/dist/types/appShell/AppLayout.d.ts +76 -0
- package/dist/types/appShell/AppearanceSettings.d.ts +41 -0
- package/dist/types/appShell/AuthLayout.d.ts +21 -0
- package/dist/types/appShell/BarActionButton.d.ts +15 -0
- package/dist/types/appShell/BarActions.d.ts +23 -0
- package/dist/types/appShell/BarCapsule.d.ts +20 -0
- package/dist/types/appShell/BarSearch.d.ts +24 -0
- package/dist/types/appShell/HeaderTools.d.ts +27 -0
- package/dist/types/appShell/MobileTabBar.d.ts +20 -0
- package/dist/types/appShell/SettingsMenu.d.ts +13 -0
- package/dist/types/appShell/SideMenu.d.ts +31 -0
- package/dist/types/appShell/SideMenuEntry.d.ts +17 -0
- package/dist/types/appShell/SubmenuActionsMenu.d.ts +24 -0
- package/dist/types/appShell/TabBarEditor.d.ts +13 -0
- package/dist/types/appShell/TopMenu.d.ts +7 -0
- package/dist/types/appShell/appMenuContext.d.ts +9 -0
- package/dist/types/appShell/barActionsSlot.d.ts +35 -0
- package/dist/types/appShell/barMenuPlacement.d.ts +9 -0
- package/dist/types/appShell/menuItemText.d.ts +55 -0
- package/dist/types/appShell/pageTitle.d.ts +26 -0
- package/dist/types/appShell/shellSizes.d.ts +46 -0
- package/dist/types/appShell/tabBarRule.d.ts +5 -0
- package/dist/types/appShell/tabBarScroll.d.ts +26 -0
- package/dist/types/appShell/useDrawerCollapsed.d.ts +8 -0
- package/dist/types/appShell/useFittingActionCount.d.ts +7 -0
- package/dist/types/appShell/usePinnedMobileTabs.d.ts +7 -0
- package/dist/types/appShell/useTabBarMinimized.d.ts +8 -0
- package/dist/types/auth/PasswordChecklist.d.ts +13 -0
- package/dist/types/auth/passwordRules.d.ts +34 -0
- package/dist/types/calendar/EventCalendar.d.ts +63 -0
- package/dist/types/calendar/EventDetails.d.ts +36 -0
- package/dist/types/calendar/calendarEvents.d.ts +27 -0
- package/dist/types/calendar.d.ts +3 -0
- package/dist/types/charts.d.ts +6 -0
- package/dist/types/date-pickers.d.ts +2 -0
- package/dist/types/datePickers/DateInput.d.ts +41 -0
- package/dist/types/datePickers/FormDateField.d.ts +7 -0
- package/dist/types/dates.d.ts +18 -0
- package/dist/types/dictionaries/dictionaries.d.ts +54 -0
- package/dist/types/downloads/DownloadManager.d.ts +7 -0
- package/dist/types/downloads/downloadQueue.d.ts +50 -0
- package/dist/types/downloads/downloadsMachine.d.ts +10 -0
- package/dist/types/downloads/fileTypes.d.ts +39 -0
- package/dist/types/downloads/index.d.ts +4 -0
- package/dist/types/excel/reportWorkbook.d.ts +157 -0
- package/dist/types/excel.d.ts +1 -0
- package/dist/types/feedback/ConfirmDialog.d.ts +31 -0
- package/dist/types/feedback/ModalWaiting.d.ts +13 -0
- package/dist/types/feedback/NewBuildNotice.d.ts +20 -0
- package/dist/types/feedback/StaleBuildBoundary.d.ts +21 -0
- package/dist/types/feedback/Toaster.d.ts +1 -0
- package/dist/types/feedback/confirmActionMachine.d.ts +19 -0
- package/dist/types/feedback/index.d.ts +8 -0
- package/dist/types/feedback/toast.d.ts +100 -0
- package/dist/types/feedback/useConfirmAction.d.ts +33 -0
- package/dist/types/filepond/FileDropzone.d.ts +61 -0
- package/dist/types/filepond/pondServer.d.ts +17 -0
- package/dist/types/filepond.d.ts +3 -0
- package/dist/types/files.d.ts +29 -0
- package/dist/types/formatting.d.ts +61 -0
- package/dist/types/forms/FormCatalogField.d.ts +6 -0
- package/dist/types/forms/FormColorField.d.ts +6 -0
- package/dist/types/forms/FormNumberField.d.ts +6 -0
- package/dist/types/forms/FormProblemAlert.d.ts +6 -0
- package/dist/types/forms/FormSelectField.d.ts +6 -0
- package/dist/types/forms/FormServerProblem.d.ts +8 -0
- package/dist/types/forms/FormTextField.d.ts +6 -0
- package/dist/types/forms/FormWizard.d.ts +22 -0
- package/dist/types/forms/SubmitButton.d.ts +9 -0
- package/dist/types/forms/applyServerProblem.d.ts +9 -0
- package/dist/types/forms/auth/ChangePasswordForm.d.ts +17 -0
- package/dist/types/forms/auth/ForgotPasswordForm.d.ts +14 -0
- package/dist/types/forms/auth/SignInForm.d.ts +20 -0
- package/dist/types/forms/index.d.ts +19 -0
- package/dist/types/forms/security/SecondStepForm.d.ts +30 -0
- package/dist/types/forms/security/TwoStepVerificationCard.d.ts +83 -0
- package/dist/types/forms/security/securityRules.d.ts +24 -0
- package/dist/types/forms/serverProblemFields.d.ts +19 -0
- package/dist/types/forms/useFormikField.d.ts +11 -0
- package/dist/types/forms/validation.d.ts +251 -0
- package/dist/types/forms/validationMessages.d.ts +12 -0
- package/dist/types/forms.d.ts +2 -0
- package/dist/types/hookForm/FormCatalogField.d.ts +8 -0
- package/dist/types/hookForm/FormColorField.d.ts +8 -0
- package/dist/types/hookForm/FormNumberField.d.ts +8 -0
- package/dist/types/hookForm/FormProblemAlert.d.ts +7 -0
- package/dist/types/hookForm/FormSelectField.d.ts +8 -0
- package/dist/types/hookForm/FormTextField.d.ts +8 -0
- package/dist/types/hookForm/FormWizard.d.ts +22 -0
- package/dist/types/hookForm/SubmitButton.d.ts +21 -0
- package/dist/types/hookForm/applyServerProblem.d.ts +10 -0
- package/dist/types/hookForm/useHookFormField.d.ts +13 -0
- package/dist/types/i18next.d.ts +1 -0
- package/dist/types/identifiers.d.ts +2 -0
- package/dist/types/inbox/InboxLayout.d.ts +38 -0
- package/dist/types/inbox/MessageList.d.ts +52 -0
- package/dist/types/inbox/MessageView.d.ts +55 -0
- package/dist/types/inbox/inboxDates.d.ts +11 -0
- package/dist/types/index.d.ts +91 -0
- package/dist/types/inputs/CatalogInput.d.ts +45 -0
- package/dist/types/inputs/ColorInput.d.ts +30 -0
- package/dist/types/inputs/FieldFrame.d.ts +14 -0
- package/dist/types/inputs/FormSection.d.ts +29 -0
- package/dist/types/inputs/NumberInput.d.ts +38 -0
- package/dist/types/inputs/SelectInput.d.ts +38 -0
- package/dist/types/inputs/TextInput.d.ts +62 -0
- package/dist/types/inputs/WizardLayout.d.ts +34 -0
- package/dist/types/inputs/colorContrast.d.ts +18 -0
- package/dist/types/inputs/formLayoutContext.d.ts +3 -0
- package/dist/types/inputs/numberText.d.ts +25 -0
- package/dist/types/kanban/KanbanBoard.d.ts +88 -0
- package/dist/types/kanban/kanbanCards.d.ts +22 -0
- package/dist/types/kanban/kanbanMoves.d.ts +38 -0
- package/dist/types/kanban.d.ts +3 -0
- package/dist/types/laravel/csrfRetry.d.ts +21 -0
- package/dist/types/laravel.d.ts +1 -0
- package/dist/types/lastListUrl.d.ts +20 -0
- package/dist/types/locales/en.d.ts +788 -0
- package/dist/types/locales/es.d.ts +788 -0
- package/dist/types/maps/MapView.d.ts +41 -0
- package/dist/types/maps/mapMarkers.d.ts +23 -0
- package/dist/types/maps.d.ts +2 -0
- package/dist/types/money/money.d.ts +203 -0
- package/dist/types/money.d.ts +1 -0
- package/dist/types/navigation/appMenu.d.ts +92 -0
- package/dist/types/navigation/useMenuBadges.d.ts +16 -0
- package/dist/types/navigation.d.ts +22 -0
- package/dist/types/navigationTrail.d.ts +49 -0
- package/dist/types/next.d.ts +1 -0
- package/dist/types/observability/buildWatch.d.ts +28 -0
- package/dist/types/observability/logger.d.ts +19 -0
- package/dist/types/observability/publishedBuild.d.ts +35 -0
- package/dist/types/observability/usePublishedBuildWatch.d.ts +18 -0
- package/dist/types/passkeys.d.ts +1 -0
- package/dist/types/periodRanges.d.ts +32 -0
- package/dist/types/problems.d.ts +31 -0
- package/dist/types/pwa/InstallAppSetting.d.ts +7 -0
- package/dist/types/pwa/InstallInstructionsDialog.d.ts +20 -0
- package/dist/types/pwa/InstallPromptBanner.d.ts +16 -0
- package/dist/types/pwa/installInstructions.d.ts +52 -0
- package/dist/types/pwa/useInstallPrompt.d.ts +13 -0
- package/dist/types/react-hook-form.d.ts +12 -0
- package/dist/types/react-router.d.ts +2 -0
- package/dist/types/security/ActivityLog.d.ts +33 -0
- package/dist/types/security/RecoveryCodesDialog.d.ts +16 -0
- package/dist/types/security/SessionsCard.d.ts +24 -0
- package/dist/types/security/passkeys.d.ts +18 -0
- package/dist/types/table.d.ts +3 -0
- package/dist/types/theme/androidDevice.d.ts +11 -0
- package/dist/types/theme/appleTracking.d.ts +17 -0
- package/dist/types/theme/components/MuiAppBar.d.ts +13 -0
- package/dist/types/theme/components/MuiBackdrop.d.ts +11 -0
- package/dist/types/theme/components/MuiButton.d.ts +27 -0
- package/dist/types/theme/components/MuiButtonBase.d.ts +14 -0
- package/dist/types/theme/components/MuiChip.d.ts +29 -0
- package/dist/types/theme/components/MuiDataGrid.d.ts +45 -0
- package/dist/types/theme/components/MuiDialog.d.ts +9 -0
- package/dist/types/theme/components/MuiDrawer.d.ts +13 -0
- package/dist/types/theme/components/MuiMenuItem.d.ts +17 -0
- package/dist/types/theme/components/MuiTypography.d.ts +20 -0
- package/dist/types/theme/components/glassComponents.d.ts +8 -0
- package/dist/types/theme/components/minimalComponents.d.ts +22 -0
- package/dist/types/theme/components/paletteOf.d.ts +5 -0
- package/dist/types/theme/createToolkitTheme.d.ts +48 -0
- package/dist/types/theme/glassSurface.d.ts +247 -0
- package/dist/types/theme/glassToasterStyles.d.ts +7 -0
- package/dist/types/theme/mergeComponents.d.ts +15 -0
- package/dist/types/theme/stackcraftPalette.d.ts +142 -0
- package/dist/types/theme/toolkitComponents.d.ts +4 -0
- package/dist/types/timeline.d.ts +2 -0
- package/dist/types/toolkit/ComponentTexts.d.ts +11 -0
- package/dist/types/toolkit/ToolkitProvider.d.ts +47 -0
- package/dist/types/toolkit/browserNavigation.d.ts +27 -0
- package/dist/types/toolkit/componentTextsContext.d.ts +20 -0
- package/dist/types/toolkit/hashNavigation.d.ts +12 -0
- package/dist/types/toolkit/navigationPaths.d.ts +43 -0
- package/dist/types/toolkit/toolkitContext.d.ts +28 -0
- package/dist/types/toolkit/toolkitSettings.d.ts +113 -0
- package/dist/types/toolkit/useFormatters.d.ts +6 -0
- package/dist/types/toolkit/useToolkitTranslation.d.ts +11 -0
- package/dist/types/ui/actions/ActionsMenu.d.ts +20 -0
- package/dist/types/ui/actions/CopyButton.d.ts +15 -0
- package/dist/types/ui/actions/DownloadMenu.d.ts +55 -0
- package/dist/types/ui/actions/SecretField.d.ts +17 -0
- package/dist/types/ui/actions/SelectionActions.d.ts +39 -0
- package/dist/types/ui/filters/DateRangeFilter.d.ts +18 -0
- package/dist/types/ui/filters/PeriodRangeSelector.d.ts +28 -0
- package/dist/types/ui/filters/QuickFilters.d.ts +23 -0
- package/dist/types/ui/filters/SegmentedControl.d.ts +44 -0
- package/dist/types/ui/index.d.ts +33 -0
- package/dist/types/ui/labels/DictionaryText.d.ts +7 -0
- package/dist/types/ui/labels/StatusChip.d.ts +21 -0
- package/dist/types/ui/labels/Tag.d.ts +19 -0
- package/dist/types/ui/labels/tagOf.d.ts +13 -0
- package/dist/types/ui/layout/CollapsibleSection.d.ts +18 -0
- package/dist/types/ui/layout/ContentDialog.d.ts +15 -0
- package/dist/types/ui/layout/DefinitionList.d.ts +15 -0
- package/dist/types/ui/layout/DetailHeader.d.ts +15 -0
- package/dist/types/ui/layout/ErrorPage.d.ts +35 -0
- package/dist/types/ui/layout/FullPageLoader.d.ts +7 -0
- package/dist/types/ui/layout/GlassLensFilter.d.ts +1 -0
- package/dist/types/ui/layout/GlassPanel.d.ts +11 -0
- package/dist/types/ui/layout/PageHeader.d.ts +15 -0
- package/dist/types/ui/layout/PageHeading.d.ts +20 -0
- package/dist/types/ui/layout/ProfileHeader.d.ts +17 -0
- package/dist/types/ui/layout/ScrollableRow.d.ts +33 -0
- package/dist/types/ui/layout/SectionCard.d.ts +11 -0
- package/dist/types/ui/layout/appBarHeight.d.ts +13 -0
- package/dist/types/ui/metrics/BarList.d.ts +25 -0
- package/dist/types/ui/metrics/CalendarHeatmap.d.ts +34 -0
- package/dist/types/ui/metrics/ChartTooltip.d.ts +11 -0
- package/dist/types/ui/metrics/ColumnChart.d.ts +47 -0
- package/dist/types/ui/metrics/LineChart.d.ts +41 -0
- package/dist/types/ui/metrics/MetricCard.d.ts +39 -0
- package/dist/types/ui/metrics/TableToggle.d.ts +14 -0
- package/dist/types/ui/metrics/barListLabels.d.ts +17 -0
- package/dist/types/ui/metrics/chartParts.d.ts +112 -0
- package/dist/types/ui/metrics/heatmapScale.d.ts +45 -0
- package/dist/types/ui/navigation/BackButton.d.ts +13 -0
- package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +13 -0
- package/dist/types/ui/navigation/DocumentTitle.d.ts +6 -0
- package/dist/types/ui/navigation/FontSizeToggle.d.ts +11 -0
- package/dist/types/ui/navigation/LanguageToggle.d.ts +13 -0
- package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +12 -0
- package/dist/types/ui/navigation/colorMode.d.ts +18 -0
- package/dist/types/ui/navigation/fontSizeLevels.d.ts +25 -0
- package/dist/types/ui/navigation/useFontSize.d.ts +10 -0
- package/dist/types/ui/timeline/GroupedTimeline.d.ts +41 -0
- package/dist/types/ui/timeline/timelineDot.d.ts +19 -0
- package/dist/types/upload/FileDropzone.d.ts +36 -0
- package/dist/types/upload/fileRules.d.ts +51 -0
- package/dist/types/upload/uploadMachine.d.ts +23 -0
- package/dist/types/upload/uploadWithProgress.d.ts +16 -0
- package/dist/ui/actions/ActionsMenu.js +51 -0
- package/dist/ui/actions/ActionsMenu.js.map +1 -0
- package/dist/ui/actions/CopyButton.js +28 -0
- package/dist/ui/actions/CopyButton.js.map +1 -0
- package/dist/ui/actions/DownloadMenu.js +162 -0
- package/dist/ui/actions/DownloadMenu.js.map +1 -0
- package/dist/ui/actions/SecretField.js +61 -0
- package/dist/ui/actions/SecretField.js.map +1 -0
- package/dist/ui/actions/SelectionActions.js +142 -0
- package/dist/ui/actions/SelectionActions.js.map +1 -0
- package/dist/ui/filters/DateRangeFilter.js +87 -0
- package/dist/ui/filters/DateRangeFilter.js.map +1 -0
- package/dist/ui/filters/PeriodRangeSelector.js +56 -0
- package/dist/ui/filters/PeriodRangeSelector.js.map +1 -0
- package/dist/ui/filters/QuickFilters.js +91 -0
- package/dist/ui/filters/QuickFilters.js.map +1 -0
- package/dist/ui/filters/SegmentedControl.js +80 -0
- package/dist/ui/filters/SegmentedControl.js.map +1 -0
- package/dist/ui/labels/DictionaryText.js +11 -0
- package/dist/ui/labels/DictionaryText.js.map +1 -0
- package/dist/ui/labels/StatusChip.js +52 -0
- package/dist/ui/labels/StatusChip.js.map +1 -0
- package/dist/ui/labels/Tag.js +26 -0
- package/dist/ui/labels/Tag.js.map +1 -0
- package/dist/ui/labels/tagOf.js +7 -0
- package/dist/ui/labels/tagOf.js.map +1 -0
- package/dist/ui/layout/CollapsibleSection.js +52 -0
- package/dist/ui/layout/CollapsibleSection.js.map +1 -0
- package/dist/ui/layout/ContentDialog.js +97 -0
- package/dist/ui/layout/ContentDialog.js.map +1 -0
- package/dist/ui/layout/DefinitionList.js +30 -0
- package/dist/ui/layout/DefinitionList.js.map +1 -0
- package/dist/ui/layout/DetailHeader.js +27 -0
- package/dist/ui/layout/DetailHeader.js.map +1 -0
- package/dist/ui/layout/ErrorPage.js +54 -0
- package/dist/ui/layout/ErrorPage.js.map +1 -0
- package/dist/ui/layout/FullPageLoader.js +13 -0
- package/dist/ui/layout/FullPageLoader.js.map +1 -0
- package/dist/ui/layout/GlassLensFilter.js +53 -0
- package/dist/ui/layout/GlassLensFilter.js.map +1 -0
- package/dist/ui/layout/GlassPanel.js +18 -0
- package/dist/ui/layout/GlassPanel.js.map +1 -0
- package/dist/ui/layout/PageHeader.js +23 -0
- package/dist/ui/layout/PageHeader.js.map +1 -0
- package/dist/ui/layout/PageHeading.js +51 -0
- package/dist/ui/layout/PageHeading.js.map +1 -0
- package/dist/ui/layout/ProfileHeader.js +64 -0
- package/dist/ui/layout/ProfileHeader.js.map +1 -0
- package/dist/ui/layout/ScrollableRow.js +156 -0
- package/dist/ui/layout/ScrollableRow.js.map +1 -0
- package/dist/ui/layout/SectionCard.js +18 -0
- package/dist/ui/layout/SectionCard.js.map +1 -0
- package/dist/ui/layout/appBarHeight.js +42 -0
- package/dist/ui/layout/appBarHeight.js.map +1 -0
- package/dist/ui/metrics/BarList.js +94 -0
- package/dist/ui/metrics/BarList.js.map +1 -0
- package/dist/ui/metrics/CalendarHeatmap.js +136 -0
- package/dist/ui/metrics/CalendarHeatmap.js.map +1 -0
- package/dist/ui/metrics/ChartTooltip.js +16 -0
- package/dist/ui/metrics/ChartTooltip.js.map +1 -0
- package/dist/ui/metrics/ColumnChart.js +106 -0
- package/dist/ui/metrics/ColumnChart.js.map +1 -0
- package/dist/ui/metrics/LineChart.js +117 -0
- package/dist/ui/metrics/LineChart.js.map +1 -0
- package/dist/ui/metrics/MetricCard.js +97 -0
- package/dist/ui/metrics/MetricCard.js.map +1 -0
- package/dist/ui/metrics/TableToggle.js +15 -0
- package/dist/ui/metrics/TableToggle.js.map +1 -0
- package/dist/ui/metrics/barListLabels.js +9 -0
- package/dist/ui/metrics/barListLabels.js.map +1 -0
- package/dist/ui/metrics/chartParts.js +93 -0
- package/dist/ui/metrics/chartParts.js.map +1 -0
- package/dist/ui/metrics/heatmapScale.js +67 -0
- package/dist/ui/metrics/heatmapScale.js.map +1 -0
- package/dist/ui/navigation/BackButton.js +28 -0
- package/dist/ui/navigation/BackButton.js.map +1 -0
- package/dist/ui/navigation/ColorSchemeToggle.js +40 -0
- package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -0
- package/dist/ui/navigation/DocumentTitle.js +11 -0
- package/dist/ui/navigation/DocumentTitle.js.map +1 -0
- package/dist/ui/navigation/FontSizeToggle.js +41 -0
- package/dist/ui/navigation/FontSizeToggle.js.map +1 -0
- package/dist/ui/navigation/LanguageToggle.js +48 -0
- package/dist/ui/navigation/LanguageToggle.js.map +1 -0
- package/dist/ui/navigation/PageBreadcrumbs.js +51 -0
- package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -0
- package/dist/ui/navigation/colorMode.js +13 -0
- package/dist/ui/navigation/colorMode.js.map +1 -0
- package/dist/ui/navigation/fontSizeLevels.js +24 -0
- package/dist/ui/navigation/fontSizeLevels.js.map +1 -0
- package/dist/ui/navigation/useFontSize.js +44 -0
- package/dist/ui/navigation/useFontSize.js.map +1 -0
- package/dist/ui/timeline/GroupedTimeline.js +106 -0
- package/dist/ui/timeline/GroupedTimeline.js.map +1 -0
- package/dist/ui/timeline/timelineDot.js +20 -0
- package/dist/ui/timeline/timelineDot.js.map +1 -0
- package/dist/upload/FileDropzone.js +145 -0
- package/dist/upload/FileDropzone.js.map +1 -0
- package/dist/upload/fileRules.js +62 -0
- package/dist/upload/fileRules.js.map +1 -0
- package/dist/upload/uploadMachine.js +73 -0
- package/dist/upload/uploadMachine.js.map +1 -0
- package/dist/upload/uploadWithProgress.js +45 -0
- package/dist/upload/uploadWithProgress.js.map +1 -0
- package/package.json +311 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restAccountConnector.js","sources":["../../src/account/restAccountConnector.js"],"sourcesContent":["// El conector de la cuenta para un backend REST que sigue este contrato (llaves en snake_case, errores RFC 9457). Si el\n// backend lo sigue, conectar la cuenta es una línea:\n//\n// export const accountConnector = createRestAccountConnector(apiClient);\n//\n// Si alguna ruta se llama distinto, se cambia en `paths`; si alguna respuesta tiene otra forma, se reemplaza esa función:\n//\n// export const accountConnector = {...createRestAccountConnector(apiClient), signIn: async (credentials) => …};\n//\n// El contrato (las rutas por omisión, ACCOUNT_REST_PATHS):\n//\n// GET /auth/session → {user, roles, abilities, labels} | 401 si nadie está dentro\n// POST /auth/sign-in {email, password, remember} → {second_step: {methods} | null}\n// POST /auth/second-step {method, code} → 204 (method: totp | recovery_code)\n// GET /auth/second-step/passkey-options → opciones de WebAuthn para firmar\n// POST /auth/second-step/passkey {credential} → 204\n// POST /auth/sign-out → 204\n// POST /auth/forgot-password {email} → 204 (igual exista o no el correo)\n// POST /auth/reset-password {token, new_password} → 204\n// PUT /account {name, phone} → {message?}\n// PUT /account/password {current_password, new_password} → 204\n// GET /account/security → el estado de la verificación (abajo)\n// POST /account/security/totp → {secret, qr_image_url}\n// POST /account/security/totp/confirm {code} → {security, recovery_codes?}\n// DELETE /account/security/totp {password} → {security}\n// GET /account/security/passkeys/registration-options → opciones de WebAuthn para crear\n// POST /account/security/passkeys {name, credential} → {security, recovery_codes?}\n// DELETE /account/security/passkeys/{id} {password} → {security}\n// POST /account/security/recovery-codes {password} → {security, recovery_codes}\n// GET /account/sessions → [{id, browser, platform, is_mobile, started_at, network, is_current}]\n// POST /account/sessions/close-others → {closed}\n// GET /account/activity → [{id, kind, occurred_at, device, network}]\n//\n// El estado de la verificación: {is_enabled, enabled_at, passkeys: [{id, name, created_at, last_used_at}],\n// totp: {is_enabled, enabled_at}, recovery_codes_remaining}. Las opciones y la firma de WebAuthn viajan tal cual (las arma\n// y las revisa la librería del servidor: py_webauthn, @simplewebauthn/server, web-auth/webauthn-lib).\n//\n// Funciones puras, no renderizan: function (regla de la casa). Pruebas en restAccountConnector.test.js.\n\n/** Las rutas del contrato; se pegan a la baseUrl del cliente (/api + /auth/session). */\nexport const ACCOUNT_REST_PATHS = Object.freeze({\n session: '/auth/session',\n signIn: '/auth/sign-in',\n secondStep: '/auth/second-step',\n secondStepPasskeyOptions: '/auth/second-step/passkey-options',\n secondStepPasskey: '/auth/second-step/passkey',\n signOut: '/auth/sign-out',\n forgotPassword: '/auth/forgot-password',\n resetPassword: '/auth/reset-password',\n profile: '/account',\n password: '/account/password',\n security: '/account/security',\n totp: '/account/security/totp',\n totpConfirm: '/account/security/totp/confirm',\n passkeyRegistrationOptions: '/account/security/passkeys/registration-options',\n passkeys: '/account/security/passkeys',\n recoveryCodes: '/account/security/recovery-codes',\n sessions: '/account/sessions',\n closeOtherSessions: '/account/sessions/close-others',\n activity: '/account/activity',\n});\n\n// cómo se llama cada método del segundo paso en el contrato (snake_case) y en las pantallas (SECOND_STEP_METHOD)\nconst SECOND_STEP_METHOD_IN_API = Object.freeze({passkey: 'passkey', totp: 'totp', recoveryCode: 'recovery_code'});\nconst SECOND_STEP_METHOD_FROM_API = Object.freeze({passkey: 'passkey', totp: 'totp', recovery_code: 'recoveryCode'});\n\n/**\n * El estado de la verificación, del contrato a camelCase.\n *\n * @param {object} response\n * @returns {import('@/account/accountConnector.js').AccountSecurity}\n */\nexport function securityFromResponse(response) {\n return {\n isEnabled: Boolean(response.is_enabled),\n enabledAt: response.enabled_at ?? null,\n passkeys: (response.passkeys ?? []).map((passkey) => ({\n id: passkey.id, name: passkey.name, createdAt: passkey.created_at, lastUsedAt: passkey.last_used_at ?? null,\n })),\n totp: {isEnabled: Boolean(response.totp?.is_enabled), enabledAt: response.totp?.enabled_at ?? null},\n recoveryCodesRemaining: response.recovery_codes_remaining ?? 0,\n };\n}\n\n/**\n * Lo que regresa un cambio de seguridad: {security, recovery_codes?} → {security, recoveryCodes?}.\n *\n * @param {object} response\n * @returns {import('@/account/accountConnector.js').AccountSecurityChange}\n */\nexport function securityChangeFromResponse(response) {\n return {security: securityFromResponse(response.security), recoveryCodes: response.recovery_codes ?? undefined};\n}\n\n/**\n * @param {{get: Function, post: Function, put: Function, delete: Function}} apiClient el de createApiClient\n * @param {{paths?: Partial<Record<keyof typeof ACCOUNT_REST_PATHS, string>>}} [options] las rutas que se llaman distinto\n * @returns {import('@/account/accountConnector.js').AccountConnector}\n */\nexport function createRestAccountConnector(apiClient, {paths = {}} = {}) {\n const path = {...ACCOUNT_REST_PATHS, ...paths};\n\n return {\n loadSession: async () => {\n try {\n // sin el aviso de «sesión vencida»: aquí que no haya sesión es una respuesta normal\n return await apiClient.get(path.session, {skipUnauthenticatedHandler: true});\n } catch (error) {\n if (error?.isUnauthenticated) {\n return null;\n }\n throw error;\n }\n },\n signIn: async ({email, password, remember}) => {\n const response = await apiClient.post(path.signIn, {email, password, remember}, {skipUnauthenticatedHandler: true});\n const methods = response?.second_step?.methods;\n return {secondStep: methods ? {methods: methods.map((method) => SECOND_STEP_METHOD_FROM_API[method] ?? method)} : null};\n },\n signInSecondStep: async ({method, code}) => {\n await apiClient.post(path.secondStep, {method: SECOND_STEP_METHOD_IN_API[method] ?? method, code}, {skipUnauthenticatedHandler: true});\n },\n secondStepPasskeyOptions: () => apiClient.get(path.secondStepPasskeyOptions, {skipUnauthenticatedHandler: true}),\n signInWithPasskey: async (credential) => {\n await apiClient.post(path.secondStepPasskey, {credential}, {skipUnauthenticatedHandler: true});\n },\n signOut: async () => {\n await apiClient.post(path.signOut, undefined, {skipUnauthenticatedHandler: true});\n },\n requestPasswordReset: async ({email}) => {\n await apiClient.post(path.forgotPassword, {email});\n },\n resetPassword: async ({token, newPassword}) => {\n await apiClient.post(path.resetPassword, {token, new_password: newPassword});\n },\n // todo lo del formulario viaja: name, phone y los campos propios de ProfileScreen (extraFields) con sus nombres\n updateProfile: async (profile) => (await apiClient.put(path.profile, profile)) ?? {},\n changePassword: async ({currentPassword, newPassword}) => {\n await apiClient.put(path.password, {current_password: currentPassword, new_password: newPassword});\n },\n loadSecurity: async () => securityFromResponse(await apiClient.get(path.security)),\n startTotp: async () => {\n const response = await apiClient.post(path.totp);\n return {secret: response.secret, qrImageUrl: response.qr_image_url ?? null};\n },\n confirmTotp: async (code) => securityChangeFromResponse(await apiClient.post(path.totpConfirm, {code})),\n disableTotp: async (password) => securityChangeFromResponse(await apiClient.delete(path.totp, {body: {password}})),\n passkeyRegistrationOptions: () => apiClient.get(path.passkeyRegistrationOptions),\n savePasskey: async ({name, credential}) => securityChangeFromResponse(await apiClient.post(path.passkeys, {name, credential})),\n removePasskey: async ({passkeyId, password}) => securityChangeFromResponse(\n await apiClient.delete(`${path.passkeys}/${encodeURIComponent(passkeyId)}`, {body: {password}}),\n ),\n regenerateRecoveryCodes: async (password) => securityChangeFromResponse(await apiClient.post(path.recoveryCodes, {password})),\n listSessions: async () => (await apiClient.get(path.sessions)).map((session) => ({\n id: session.id, browser: session.browser, platform: session.platform, isMobile: Boolean(session.is_mobile),\n startedAt: session.started_at, network: session.network, isCurrent: Boolean(session.is_current),\n })),\n closeOtherSessions: async () => (await apiClient.post(path.closeOtherSessions))?.closed ?? 0,\n listActivity: async () => (await apiClient.get(path.activity)).map((event) => ({\n id: event.id, kind: event.kind, occurredAt: event.occurred_at, device: event.device, network: event.network,\n })),\n };\n}\n"],"names":[],"mappings":"AAwCY,MAAC,qBAAqB,OAAO,OAAO;AAAA,EAC5C,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AAAA,EACV,MAAM;AAAA,EACN,aAAa;AAAA,EACb,4BAA4B;AAAA,EAC5B,UAAU;AAAA,EACV,eAAe;AAAA,EACf,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,UAAU;AACd,CAAC;AAGD,MAAM,4BAA4B,OAAO,OAAO,EAAC,SAAS,WAAW,MAAM,QAAQ,cAAc,gBAAe,CAAC;AACjH,MAAM,8BAA8B,OAAO,OAAO,EAAC,SAAS,WAAW,MAAM,QAAQ,eAAe,eAAc,CAAC;AAQ5G,SAAS,qBAAqB,UAAU;AAC3C,SAAO;AAAA,IACH,WAAW,QAAQ,SAAS,UAAU;AAAA,IACtC,WAAW,SAAS,cAAc;AAAA,IAClC,WAAW,SAAS,YAAY,CAAA,GAAI,IAAI,CAAC,aAAa;AAAA,MAClD,IAAI,QAAQ;AAAA,MAAI,MAAM,QAAQ;AAAA,MAAM,WAAW,QAAQ;AAAA,MAAY,YAAY,QAAQ,gBAAgB;AAAA,IACnH,EAAU;AAAA,IACF,MAAM,EAAC,WAAW,QAAQ,SAAS,MAAM,UAAU,GAAG,WAAW,SAAS,MAAM,cAAc,KAAI;AAAA,IAClG,wBAAwB,SAAS,4BAA4B;AAAA,EACrE;AACA;AAQO,SAAS,2BAA2B,UAAU;AACjD,SAAO,EAAC,UAAU,qBAAqB,SAAS,QAAQ,GAAG,eAAe,SAAS,kBAAkB,OAAS;AAClH;AAOO,SAAS,2BAA2B,WAAW,EAAC,QAAQ,CAAA,EAAE,IAAI,CAAA,GAAI;AACrE,QAAM,OAAO,EAAC,GAAG,oBAAoB,GAAG,MAAK;AAE7C,SAAO;AAAA,IACH,aAAa,YAAY;AACrB,UAAI;AAEA,eAAO,MAAM,UAAU,IAAI,KAAK,SAAS,EAAC,4BAA4B,KAAI,CAAC;AAAA,MAC/E,SAAS,OAAO;AACZ,YAAI,OAAO,mBAAmB;AAC1B,iBAAO;AAAA,QACX;AACA,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,IACA,QAAQ,OAAO,EAAC,OAAO,UAAU,SAAQ,MAAM;AAC3C,YAAM,WAAW,MAAM,UAAU,KAAK,KAAK,QAAQ,EAAC,OAAO,UAAU,SAAQ,GAAG,EAAC,4BAA4B,KAAI,CAAC;AAClH,YAAM,UAAU,UAAU,aAAa;AACvC,aAAO,EAAC,YAAY,UAAU,EAAC,SAAS,QAAQ,IAAI,CAAC,WAAW,4BAA4B,MAAM,KAAK,MAAM,EAAC,IAAI,KAAI;AAAA,IAC1H;AAAA,IACA,kBAAkB,OAAO,EAAC,QAAQ,KAAI,MAAM;AACxC,YAAM,UAAU,KAAK,KAAK,YAAY,EAAC,QAAQ,0BAA0B,MAAM,KAAK,QAAQ,KAAI,GAAG,EAAC,4BAA4B,KAAI,CAAC;AAAA,IACzI;AAAA,IACA,0BAA0B,MAAM,UAAU,IAAI,KAAK,0BAA0B,EAAC,4BAA4B,KAAI,CAAC;AAAA,IAC/G,mBAAmB,OAAO,eAAe;AACrC,YAAM,UAAU,KAAK,KAAK,mBAAmB,EAAC,WAAU,GAAG,EAAC,4BAA4B,KAAI,CAAC;AAAA,IACjG;AAAA,IACA,SAAS,YAAY;AACjB,YAAM,UAAU,KAAK,KAAK,SAAS,QAAW,EAAC,4BAA4B,KAAI,CAAC;AAAA,IACpF;AAAA,IACA,sBAAsB,OAAO,EAAC,MAAK,MAAM;AACrC,YAAM,UAAU,KAAK,KAAK,gBAAgB,EAAC,MAAK,CAAC;AAAA,IACrD;AAAA,IACA,eAAe,OAAO,EAAC,OAAO,YAAW,MAAM;AAC3C,YAAM,UAAU,KAAK,KAAK,eAAe,EAAC,OAAO,cAAc,YAAW,CAAC;AAAA,IAC/E;AAAA;AAAA,IAEA,eAAe,OAAO,YAAa,MAAM,UAAU,IAAI,KAAK,SAAS,OAAO,KAAM,CAAA;AAAA,IAClF,gBAAgB,OAAO,EAAC,iBAAiB,YAAW,MAAM;AACtD,YAAM,UAAU,IAAI,KAAK,UAAU,EAAC,kBAAkB,iBAAiB,cAAc,YAAW,CAAC;AAAA,IACrG;AAAA,IACA,cAAc,YAAY,qBAAqB,MAAM,UAAU,IAAI,KAAK,QAAQ,CAAC;AAAA,IACjF,WAAW,YAAY;AACnB,YAAM,WAAW,MAAM,UAAU,KAAK,KAAK,IAAI;AAC/C,aAAO,EAAC,QAAQ,SAAS,QAAQ,YAAY,SAAS,gBAAgB,KAAI;AAAA,IAC9E;AAAA,IACA,aAAa,OAAO,SAAS,2BAA2B,MAAM,UAAU,KAAK,KAAK,aAAa,EAAC,KAAI,CAAC,CAAC;AAAA,IACtG,aAAa,OAAO,aAAa,2BAA2B,MAAM,UAAU,OAAO,KAAK,MAAM,EAAC,MAAM,EAAC,SAAQ,EAAC,CAAC,CAAC;AAAA,IACjH,4BAA4B,MAAM,UAAU,IAAI,KAAK,0BAA0B;AAAA,IAC/E,aAAa,OAAO,EAAC,MAAM,WAAU,MAAM,2BAA2B,MAAM,UAAU,KAAK,KAAK,UAAU,EAAC,MAAM,WAAU,CAAC,CAAC;AAAA,IAC7H,eAAe,OAAO,EAAC,WAAW,SAAQ,MAAM;AAAA,MAC5C,MAAM,UAAU,OAAO,GAAG,KAAK,QAAQ,IAAI,mBAAmB,SAAS,CAAC,IAAI,EAAC,MAAM,EAAC,SAAQ,EAAC,CAAC;AAAA,IAC1G;AAAA,IACQ,yBAAyB,OAAO,aAAa,2BAA2B,MAAM,UAAU,KAAK,KAAK,eAAe,EAAC,SAAQ,CAAC,CAAC;AAAA,IAC5H,cAAc,aAAa,MAAM,UAAU,IAAI,KAAK,QAAQ,GAAG,IAAI,CAAC,aAAa;AAAA,MAC7E,IAAI,QAAQ;AAAA,MAAI,SAAS,QAAQ;AAAA,MAAS,UAAU,QAAQ;AAAA,MAAU,UAAU,QAAQ,QAAQ,SAAS;AAAA,MACzG,WAAW,QAAQ;AAAA,MAAY,SAAS,QAAQ;AAAA,MAAS,WAAW,QAAQ,QAAQ,UAAU;AAAA,IAC1G,EAAU;AAAA,IACF,oBAAoB,aAAa,MAAM,UAAU,KAAK,KAAK,kBAAkB,IAAI,UAAU;AAAA,IAC3F,cAAc,aAAa,MAAM,UAAU,IAAI,KAAK,QAAQ,GAAG,IAAI,CAAC,WAAW;AAAA,MAC3E,IAAI,MAAM;AAAA,MAAI,MAAM,MAAM;AAAA,MAAM,YAAY,MAAM;AAAA,MAAa,QAAQ,MAAM;AAAA,MAAQ,SAAS,MAAM;AAAA,IAChH,EAAU;AAAA,EACV;AACA;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createDemoAccountConnector } from "./account/demo/createDemoAccountConnector.js";
|
|
2
|
+
import { base32Of, bytesOfBase32, isValidTotpCode, newTotpSecret, otpauthUrlOf, totpCodeAt } from "./account/demo/totp.js";
|
|
3
|
+
export {
|
|
4
|
+
base32Of,
|
|
5
|
+
bytesOfBase32,
|
|
6
|
+
createDemoAccountConnector,
|
|
7
|
+
isValidTotpCode,
|
|
8
|
+
newTotpSecret,
|
|
9
|
+
otpauthUrlOf,
|
|
10
|
+
totpCodeAt
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=account-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account-demo.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/dist/account.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ACCOUNT_CONNECTOR_FUNCTIONS, missingConnectorFunctionsOf } from "./account/accountConnector.js";
|
|
2
|
+
import { ACCOUNT_REST_PATHS, createRestAccountConnector, securityChangeFromResponse, securityFromResponse } from "./account/restAccountConnector.js";
|
|
3
|
+
import { default as default2, useAccount } from "./account/AccountProvider.js";
|
|
4
|
+
import { default as default3 } from "./account/AccountSecuritySection.js";
|
|
5
|
+
import { default as default4 } from "./account/ForgotPasswordScreen.js";
|
|
6
|
+
import { PROFILE_TAB, default as default5 } from "./account/ProfileScreen.js";
|
|
7
|
+
import { default as default6 } from "./account/ResetPasswordScreen.js";
|
|
8
|
+
import { default as default7 } from "./account/SignInScreen.js";
|
|
9
|
+
export {
|
|
10
|
+
ACCOUNT_CONNECTOR_FUNCTIONS,
|
|
11
|
+
ACCOUNT_REST_PATHS,
|
|
12
|
+
default2 as AccountProvider,
|
|
13
|
+
default3 as AccountSecuritySection,
|
|
14
|
+
default4 as ForgotPasswordScreen,
|
|
15
|
+
PROFILE_TAB,
|
|
16
|
+
default5 as ProfileScreen,
|
|
17
|
+
default6 as ResetPasswordScreen,
|
|
18
|
+
default7 as SignInScreen,
|
|
19
|
+
createRestAccountConnector,
|
|
20
|
+
missingConnectorFunctionsOf,
|
|
21
|
+
securityChangeFromResponse,
|
|
22
|
+
securityFromResponse,
|
|
23
|
+
useAccount
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18next.js","sources":["../../src/adapters/i18next.js"],"sourcesContent":["// Los textos del paquete desde i18next, para un proyecto que ya lo usa: el proyecto escribe sus textos en sus\n// namespaces de siempre (table, common, problems, validation, dictionaries) y lo que no escriba sale del paquete.\n//\n// <ToolkitProvider language={i18n.resolvedLanguage} onLanguageChange={(language) => i18n.changeLanguage(language)}\n// translate={translateWithI18next(i18n)}>\n//\n// No importa i18next: recibe la instancia del proyecto.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\n\n/**\n * El traductor de ToolkitProvider sobre una instancia de i18next: si la llave existe en el proyecto regresa su texto;\n * si no, undefined, y el paquete usa el suyo.\n *\n * @param {{exists: Function, t: Function}} i18n la instancia de i18next del proyecto\n * @returns {(namespace: string, key: string, values?: object) => string|undefined}\n */\nexport function translateWithI18next(i18n) {\n return (namespace, key, values) => (i18n.exists(key, {ns: namespace}) ? i18n.t(key, {ns: namespace, ...values}) : undefined);\n}\n"],"names":[],"mappings":"AAiBO,SAAS,qBAAqB,MAAM;AACvC,SAAO,CAAC,WAAW,KAAK,WAAY,KAAK,OAAO,KAAK,EAAC,IAAI,UAAS,CAAC,IAAI,KAAK,EAAE,KAAK,EAAC,IAAI,WAAW,GAAG,OAAM,CAAC,IAAI;AACtH;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import NextLink from "next/link";
|
|
5
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
6
|
+
function useNextNavigate() {
|
|
7
|
+
const router = useRouter();
|
|
8
|
+
return useCallback((to, options) => {
|
|
9
|
+
if (typeof to === "number") {
|
|
10
|
+
if (to < 0) {
|
|
11
|
+
router.back();
|
|
12
|
+
} else {
|
|
13
|
+
router.forward();
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (options?.replace) {
|
|
18
|
+
router.replace(to);
|
|
19
|
+
} else {
|
|
20
|
+
router.push(to);
|
|
21
|
+
}
|
|
22
|
+
}, [router]);
|
|
23
|
+
}
|
|
24
|
+
function useNextLocation() {
|
|
25
|
+
const pathname = usePathname();
|
|
26
|
+
const search = typeof window === "undefined" ? "" : window.location.search;
|
|
27
|
+
return { pathname, search, key: `${pathname}${search}` };
|
|
28
|
+
}
|
|
29
|
+
function NextToLink({ to, href, ...linkProps }) {
|
|
30
|
+
return /* @__PURE__ */ jsx(NextLink, { href: to ?? href, ...linkProps });
|
|
31
|
+
}
|
|
32
|
+
const nextNavigation = Object.freeze({ useNavigate: useNextNavigate, useLocation: useNextLocation, Link: NextToLink });
|
|
33
|
+
export {
|
|
34
|
+
nextNavigation
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=nextNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextNavigation.js","sources":["../../src/adapters/nextNavigation.jsx"],"sourcesContent":["// La navegación de Next.js (App Router) para ToolkitProvider (@stackcraftmx/calcita/next): las tres piezas que piden los\n// componentes del framework, sacadas de next/navigation y next/link.\n//\n// <ToolkitProvider navigation={nextNavigation}> (dentro de un componente de cliente: el de los proveedores)\n//\n// Decisiones, con su porqué:\n// - search se lee del navegador al pintar y NO con useSearchParams: useSearchParams obliga a envolver la página en\n// <Suspense> (si no, `next build` truena con «Missing Suspense boundary»). En el servidor no hay búsqueda: ''.\n// - useNavigate(-1) regresa (router.back): BackButton lo usa cuando hay historial.\n// - Link recibe `to` (como los componentes del framework, y como MUI con component={Link}) y se lo da a next/link como\n// href.\n// OJO: el «Regresar» que dice a dónde regresa (navigationTrail) lee el índice del historial que pone react-router; con\n// Next no existe, así que BackButton regresa a la última lista anotada o a fallbackTo.\n//\n// Genéricos del paquete: function (regla de la casa).\nimport {useCallback} from 'react';\nimport NextLink from 'next/link';\nimport {usePathname, useRouter} from 'next/navigation';\n\n/**\n * navigate(to) del framework con el router de Next.\n *\n * @returns {(to: string|number, options?: {replace?: boolean}) => void}\n */\nfunction useNextNavigate() {\n const router = useRouter();\n return useCallback((to, options) => {\n if (typeof to === 'number') {\n if (to < 0) {\n router.back();\n } else {\n router.forward();\n }\n return;\n }\n if (options?.replace) {\n router.replace(to);\n } else {\n router.push(to);\n }\n }, [router]);\n}\n\n/**\n * {pathname, search, key} de la página abierta.\n *\n * @returns {{pathname: string, search: string, key: string}}\n */\nfunction useNextLocation() {\n const pathname = usePathname();\n const search = typeof window === 'undefined' ? '' : window.location.search;\n return {pathname, search, key: `${pathname}${search}`};\n}\n\n/**\n * next/link con la prop `to` del framework.\n *\n * @param {{to?: string, href?: string}} props\n */\nfunction NextToLink({to, href, ...linkProps}) {\n return <NextLink href={to ?? href} {...linkProps} />;\n}\n\nexport const nextNavigation = Object.freeze({useNavigate: useNextNavigate, useLocation: useNextLocation, Link: NextToLink});\n"],"names":[],"mappings":";;;;;AAwBA,SAAS,kBAAkB;AACvB,QAAM,SAAS,UAAA;AACf,SAAO,YAAY,CAAC,IAAI,YAAY;AAChC,QAAI,OAAO,OAAO,UAAU;AACxB,UAAI,KAAK,GAAG;AACR,eAAO,KAAA;AAAA,MACX,OAAO;AACH,eAAO,QAAA;AAAA,MACX;AACA;AAAA,IACJ;AACA,QAAI,SAAS,SAAS;AAClB,aAAO,QAAQ,EAAE;AAAA,IACrB,OAAO;AACH,aAAO,KAAK,EAAE;AAAA,IAClB;AAAA,EACJ,GAAG,CAAC,MAAM,CAAC;AACf;AAOA,SAAS,kBAAkB;AACvB,QAAM,WAAW,YAAA;AACjB,QAAM,SAAS,OAAO,WAAW,cAAc,KAAK,OAAO,SAAS;AACpE,SAAO,EAAC,UAAU,QAAQ,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAA;AACvD;AAOA,SAAS,WAAW,EAAC,IAAI,MAAM,GAAG,aAAY;AAC1C,6BAAQ,UAAA,EAAS,MAAM,MAAM,MAAO,GAAG,WAAW;AACtD;AAEO,MAAM,iBAAiB,OAAO,OAAO,EAAC,aAAa,iBAAiB,aAAa,iBAAiB,MAAM,WAAA,CAAW;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouter.js","sources":["../../src/adapters/reactRouter.js"],"sourcesContent":["// La navegación de react-router para ToolkitProvider: tiene justo las tres piezas que piden los componentes del paquete.\n//\n// <ToolkitProvider navigation={reactRouterNavigation}>\n//\n// Va dentro del router (RouterProvider o BrowserRouter), porque sus hooks leen el router.\nimport {Link, useLocation, useNavigate} from 'react-router';\n\nexport const reactRouterNavigation = Object.freeze({useNavigate, useLocation, Link});\n"],"names":[],"mappings":";;AAOY,MAAC,wBAAwB,OAAO,OAAO,EAAC,aAAa,aAAa,KAAI,CAAC;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { useRouteError, isRouteErrorResponse, useNavigation, useOutletContext, Outlet } from "react-router";
|
|
5
|
+
import RequireAccess from "../access/RequireAccess.js";
|
|
6
|
+
import { isStaleChunkError, recoverFromStaleChunk } from "../api/staleChunks.js";
|
|
7
|
+
import { createLogger } from "../observability/logger.js";
|
|
8
|
+
import ErrorPage, { ERROR_PAGE_KIND } from "../ui/layout/ErrorPage.js";
|
|
9
|
+
const log = createLogger("navigation");
|
|
10
|
+
const NOT_FOUND_STATUS = 404;
|
|
11
|
+
function AccessOutlet({ access, fallback }) {
|
|
12
|
+
const parentContext = useOutletContext();
|
|
13
|
+
return /* @__PURE__ */ jsx(RequireAccess, { access, fallback, children: /* @__PURE__ */ jsx(Outlet, { context: parentContext }) });
|
|
14
|
+
}
|
|
15
|
+
function withAccess(access, routes, { fallback } = {}) {
|
|
16
|
+
return { element: /* @__PURE__ */ jsx(AccessOutlet, { access, fallback }), children: routes };
|
|
17
|
+
}
|
|
18
|
+
function useIsNavigating() {
|
|
19
|
+
return useNavigation().state === "loading";
|
|
20
|
+
}
|
|
21
|
+
function withChunkRecovery(routes) {
|
|
22
|
+
return routes.map((route) => ({
|
|
23
|
+
...route,
|
|
24
|
+
...typeof route.lazy === "function" && { lazy: () => route.lazy().catch(recoverFromStaleChunk) },
|
|
25
|
+
...route.children && { children: withChunkRecovery(route.children) }
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
function reloadPage() {
|
|
29
|
+
window.location.reload();
|
|
30
|
+
}
|
|
31
|
+
function RouteErrorScreen({ onError, ...errorPageProps } = {}) {
|
|
32
|
+
const error = useRouteError();
|
|
33
|
+
const isNotFound = isRouteErrorResponse(error) && error.status === NOT_FOUND_STATUS;
|
|
34
|
+
const kind = isNotFound ? ERROR_PAGE_KIND.notFound : isStaleChunkError(error) ? ERROR_PAGE_KIND.newVersion : ERROR_PAGE_KIND.serverError;
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!isNotFound) {
|
|
37
|
+
log.error("una pantalla no se pudo pintar", { name: error?.name, message: error?.message ?? String(error) });
|
|
38
|
+
}
|
|
39
|
+
onError?.(error, kind);
|
|
40
|
+
}, [error, isNotFound]);
|
|
41
|
+
return /* @__PURE__ */ jsx(ErrorPage, { kind, onRetry: isNotFound ? void 0 : reloadPage, ...errorPageProps });
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
RouteErrorScreen,
|
|
45
|
+
useIsNavigating,
|
|
46
|
+
withAccess,
|
|
47
|
+
withChunkRecovery
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=reactRouterRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactRouterRoutes.js","sources":["../../src/adapters/reactRouterRoutes.jsx"],"sourcesContent":["// Lo que conecta los permisos y la barra con react-router (@stackcraftmx/calcita/react-router):\n//\n// withAccess(access, routes) un grupo de rutas con la regla del menu.js de su módulo: quien no puede ve la página de\n// «sin permiso» en lugar de la pantalla\n// useIsNavigating() la pantalla siguiente se está descargando (rutas lazy): para la rayita de AppLayout\n// withChunkRecovery(routes) las rutas lazy recargan UNA vez si su archivo es de una versión que ya no existe\n// RouteErrorScreen la pantalla de error de una ruta (errorElement / ErrorBoundary del router): «Hay una\n// versión nueva» o «Algo falló», con su botón para recargar\n//\n// import {access} from '@/modules/users/menu.js';\n// import {routes} from '@/modules/users/routes.js';\n// children: [withAccess(access, routes)]\n//\n// OJO: useIsNavigating solo funciona con un router de datos (createBrowserRouter); con <BrowserRouter> no hay estado de\n// navegación.\n//\n// Genéricos del paquete: function (regla de la casa).\nimport {useEffect} from 'react';\nimport {Outlet, isRouteErrorResponse, useNavigation, useOutletContext, useRouteError} from 'react-router';\n\nimport RequireAccess from '@/access/RequireAccess.jsx';\nimport {isStaleChunkError, recoverFromStaleChunk} from '@/api/staleChunks.js';\nimport {createLogger} from '@/observability/logger.js';\nimport ErrorPage, {ERROR_PAGE_KIND} from '@/ui/layout/ErrorPage.jsx';\n\nconst log = createLogger('navigation');\nconst NOT_FOUND_STATUS = 404;\n\n/**\n * El grupo con permiso: RequireAccess alrededor de las rutas hijas.\n *\n * OJO, trampa pagada: un <Outlet /> nuevo corta el contexto que la ruta de arriba le pasa a sus hijas (<Outlet\n * context={...} />, useOutletContext); el inicio de los ejemplos tronaba sin el menú. Aquí se pasa tal cual.\n *\n * @param {{access: object|undefined, fallback?: import('react').ReactNode}} props\n */\nfunction AccessOutlet({access, fallback}) {\n const parentContext = useOutletContext();\n return <RequireAccess access={access} fallback={fallback}><Outlet context={parentContext} /></RequireAccess>;\n}\n\n/**\n * Un grupo de rutas sin camino propio que pide permiso antes de pintar a sus hijas.\n *\n * @param {object|undefined} access la regla (accessRules.js); sin ella, el grupo es de todos\n * @param {object[]} routes las rutas del módulo\n * @param {{fallback?: import('react').ReactNode}} [options] fallback: lo que ve quien no tiene permiso; por omisión la página\n * de «sin permiso» de la casa (con ErrorPage y sus props se arma una propia: un botón para pedir acceso)\n * @returns {object} la ruta de react-router\n */\nexport function withAccess(access, routes, {fallback} = {}) {\n return {element: <AccessOutlet access={access} fallback={fallback} />, children: routes};\n}\n\n/**\n * ¿Se está descargando la pantalla siguiente?\n *\n * @returns {boolean}\n */\nexport function useIsNavigating() {\n return useNavigation().state === 'loading';\n}\n\n/**\n * Las rutas con la recuperación de archivos viejos (staleChunks.js): cada `lazy`, también la de las hijas, recarga la\n * página UNA vez si el archivo de su pantalla ya no existe porque se publicó otra versión. Lo demás de la ruta no cambia.\n *\n * @param {object[]} routes\n * @returns {object[]}\n */\nexport function withChunkRecovery(routes) {\n return routes.map((route) => ({\n ...route,\n ...(typeof route.lazy === 'function' && {lazy: () => route.lazy().catch(recoverFromStaleChunk)}),\n ...(route.children && {children: withChunkRecovery(route.children)}),\n }));\n}\n\n/** Recargar la página: trae la versión publicada. */\nfunction reloadPage() {\n window.location.reload();\n}\n\n/**\n * La pantalla de error de una ruta (la que el router enseña cuando la pantalla truena o no se pudo descargar): una ruta\n * que no existe es «Esta página no existe»; un archivo de otra versión, «Hay una versión nueva»; lo demás, «Algo falló de\n * nuestro lado». Las dos últimas con su botón para recargar.\n *\n * createBrowserRouter([{path: '/', element: <App />, ErrorBoundary: RouteErrorScreen, children: [...]}])\n *\n * Con props (como errorElement) se extiende igual que ErrorPage, y onError recibe lo que tronó (para Sentry o su aviso):\n * {errorElement: <RouteErrorScreen onError={(error) => reportError(error)} extraActions={<SupportButton />} />}\n *\n * @param {object} [props] las de ErrorPage (extraActions, actions, children, icon, homePath, onGoHome, texts) y:\n * @param {(error: unknown, kind: string) => void} [props.onError] cada error que llega aquí, con su tipo (ERROR_PAGE_KIND)\n */\nexport function RouteErrorScreen({onError, ...errorPageProps} = {}) {\n const error = useRouteError();\n const isNotFound = isRouteErrorResponse(error) && error.status === NOT_FOUND_STATUS;\n const kind = isNotFound ? ERROR_PAGE_KIND.notFound : (isStaleChunkError(error) ? ERROR_PAGE_KIND.newVersion : ERROR_PAGE_KIND.serverError);\n\n useEffect(() => {\n if (!isNotFound) {\n log.error('una pantalla no se pudo pintar', {name: error?.name, message: error?.message ?? String(error)});\n }\n onError?.(error, kind);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [error, isNotFound]);\n\n return <ErrorPage kind={kind} onRetry={isNotFound ? undefined : reloadPage} {...errorPageProps} />;\n}\n"],"names":[],"mappings":";;;;;;;;AAyBA,MAAM,MAAM,aAAa,YAAY;AACrC,MAAM,mBAAmB;AAUzB,SAAS,aAAa,EAAC,QAAQ,YAAW;AACtC,QAAM,gBAAgB,iBAAA;AACtB,SAAO,oBAAC,iBAAc,QAAgB,UAAoB,8BAAC,QAAA,EAAO,SAAS,eAAe,EAAA,CAAE;AAChG;AAWO,SAAS,WAAW,QAAQ,QAAQ,EAAC,SAAA,IAAY,CAAA,GAAI;AACxD,SAAO,EAAC,SAAS,oBAAC,cAAA,EAAa,QAAgB,SAAA,CAAoB,GAAI,UAAU,OAAA;AACrF;AAOO,SAAS,kBAAkB;AAC9B,SAAO,cAAA,EAAgB,UAAU;AACrC;AASO,SAAS,kBAAkB,QAAQ;AACtC,SAAO,OAAO,IAAI,CAAC,WAAW;AAAA,IAC1B,GAAG;AAAA,IACH,GAAI,OAAO,MAAM,SAAS,cAAc,EAAC,MAAM,MAAM,MAAM,KAAA,EAAO,MAAM,qBAAqB,EAAA;AAAA,IAC7F,GAAI,MAAM,YAAY,EAAC,UAAU,kBAAkB,MAAM,QAAQ,EAAA;AAAA,EAAC,EACpE;AACN;AAGA,SAAS,aAAa;AAClB,SAAO,SAAS,OAAA;AACpB;AAeO,SAAS,iBAAiB,EAAC,SAAS,GAAG,eAAA,IAAkB,CAAA,GAAI;AAChE,QAAM,QAAQ,cAAA;AACd,QAAM,aAAa,qBAAqB,KAAK,KAAK,MAAM,WAAW;AACnE,QAAM,OAAO,aAAa,gBAAgB,WAAY,kBAAkB,KAAK,IAAI,gBAAgB,aAAa,gBAAgB;AAE9H,YAAU,MAAM;AACZ,QAAI,CAAC,YAAY;AACb,UAAI,MAAM,kCAAkC,EAAC,MAAM,OAAO,MAAM,SAAS,OAAO,WAAW,OAAO,KAAK,EAAA,CAAE;AAAA,IAC7G;AACA,cAAU,OAAO,IAAI;AAAA,EAEzB,GAAG,CAAC,OAAO,UAAU,CAAC;AAEtB,SAAO,oBAAC,aAAU,MAAY,SAAS,aAAa,SAAY,YAAa,GAAG,gBAAgB;AACpG;"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { problemMessage, problemTitle } from "../problems.js";
|
|
2
|
+
const API_ERROR_STATUS = Object.freeze({
|
|
3
|
+
// no hubo respuesta: red caída, servidor apagado o se acabó el tiempo
|
|
4
|
+
offline: 0,
|
|
5
|
+
unauthenticated: 401,
|
|
6
|
+
forbidden: 403,
|
|
7
|
+
notFound: 404,
|
|
8
|
+
// el registro no está en el estado que la acción necesita (p. ej. cerrar un mes que no está completo)
|
|
9
|
+
conflict: 409,
|
|
10
|
+
// la liga ya venció, ya se usó o no existe
|
|
11
|
+
gone: 410,
|
|
12
|
+
validation: 422,
|
|
13
|
+
tooManyRequests: 429
|
|
14
|
+
});
|
|
15
|
+
class ApiError extends Error {
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} details
|
|
18
|
+
* @param {number} details.status el status HTTP; 0 si no hubo respuesta
|
|
19
|
+
* @param {object|null} [details.problem] el cuerpo RFC 9457 del servidor ({title, detail, code, errors, request_id})
|
|
20
|
+
* @param {boolean} [details.translatedByServer] false si la respuesta llegó en otro idioma que el pedido
|
|
21
|
+
* @param {number|null} [details.retryAfterSeconds] 429: los segundos del header Retry-After
|
|
22
|
+
*/
|
|
23
|
+
constructor({ status, problem = null, translatedByServer = true, retryAfterSeconds = null }) {
|
|
24
|
+
super(problemMessage(problem, status, { translatedByServer }));
|
|
25
|
+
this.name = "ApiError";
|
|
26
|
+
this.status = status;
|
|
27
|
+
this.problem = problem ?? {};
|
|
28
|
+
this.code = problem?.code ?? (status === API_ERROR_STATUS.offline ? "offline" : null);
|
|
29
|
+
this.title = problemTitle(problem, status, { translatedByServer });
|
|
30
|
+
this.requestId = problem?.request_id ?? null;
|
|
31
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
32
|
+
}
|
|
33
|
+
/** No hubo respuesta del servidor (red caída, servidor apagado, se acabó el tiempo). */
|
|
34
|
+
get isOffline() {
|
|
35
|
+
return this.status === API_ERROR_STATUS.offline;
|
|
36
|
+
}
|
|
37
|
+
/** Sin sesión, o se venció mientras se usaba la app. */
|
|
38
|
+
get isUnauthenticated() {
|
|
39
|
+
return this.status === API_ERROR_STATUS.unauthenticated;
|
|
40
|
+
}
|
|
41
|
+
/** El registro no está en el estado que la acción necesita. */
|
|
42
|
+
get isConflict() {
|
|
43
|
+
return this.status === API_ERROR_STATUS.conflict;
|
|
44
|
+
}
|
|
45
|
+
/** La liga venció, ya se usó o no existe. */
|
|
46
|
+
get isGone() {
|
|
47
|
+
return this.status === API_ERROR_STATUS.gone;
|
|
48
|
+
}
|
|
49
|
+
/** Errores de un formulario: los mensajes por campo van en problem.errors (fieldErrorsOf). */
|
|
50
|
+
get isValidation() {
|
|
51
|
+
return this.status === API_ERROR_STATUS.validation;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
API_ERROR_STATUS,
|
|
56
|
+
ApiError
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=ApiError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiError.js","sources":["../../src/api/ApiError.js"],"sourcesContent":["// El error de cualquier petición al servidor, con la misma forma siempre: un error del servidor (RFC 9457), una red caída\n// o un archivo que llegó cortado. Así la pantalla tiene UNA forma de error que enseñar y no dos.\n//\n// El mensaje ya viene en el idioma de la persona: si el servidor lo mandó traducido (title y detail en el idioma de\n// Accept-Language) se usa tal cual; si no (sin red, un 502 del proxy en HTML, una respuesta en otro idioma), el texto\n// genérico del paquete según el status (problems.js).\n//\n// Lo usan los formularios (applyServerProblem: los errores de un 422 van a su campo), toastProblem, la tabla, las\n// descargas y la subida de archivos.\n//\n// Una clase porque es un Error (trae su pila y `instanceof ApiError` funciona); lo demás del paquete son funciones.\nimport {problemMessage, problemTitle} from '@/problems.js';\n\n/** Los status que la pantalla suele tratar distinto, con su nombre. */\nexport const API_ERROR_STATUS = Object.freeze({\n // no hubo respuesta: red caída, servidor apagado o se acabó el tiempo\n offline: 0,\n unauthenticated: 401,\n forbidden: 403,\n notFound: 404,\n // el registro no está en el estado que la acción necesita (p. ej. cerrar un mes que no está completo)\n conflict: 409,\n // la liga ya venció, ya se usó o no existe\n gone: 410,\n validation: 422,\n tooManyRequests: 429,\n});\n\nexport class ApiError extends Error {\n /**\n * @param {object} details\n * @param {number} details.status el status HTTP; 0 si no hubo respuesta\n * @param {object|null} [details.problem] el cuerpo RFC 9457 del servidor ({title, detail, code, errors, request_id})\n * @param {boolean} [details.translatedByServer] false si la respuesta llegó en otro idioma que el pedido\n * @param {number|null} [details.retryAfterSeconds] 429: los segundos del header Retry-After\n */\n constructor({status, problem = null, translatedByServer = true, retryAfterSeconds = null}) {\n super(problemMessage(problem, status, {translatedByServer}));\n this.name = 'ApiError';\n this.status = status;\n this.problem = problem ?? {};\n this.code = problem?.code ?? (status === API_ERROR_STATUS.offline ? 'offline' : null);\n this.title = problemTitle(problem, status, {translatedByServer});\n // el id con que el servidor guardó el error en su bitácora: lo que se le pasa a soporte\n this.requestId = problem?.request_id ?? null;\n this.retryAfterSeconds = retryAfterSeconds;\n }\n\n /** No hubo respuesta del servidor (red caída, servidor apagado, se acabó el tiempo). */\n get isOffline() {\n return this.status === API_ERROR_STATUS.offline;\n }\n\n /** Sin sesión, o se venció mientras se usaba la app. */\n get isUnauthenticated() {\n return this.status === API_ERROR_STATUS.unauthenticated;\n }\n\n /** El registro no está en el estado que la acción necesita. */\n get isConflict() {\n return this.status === API_ERROR_STATUS.conflict;\n }\n\n /** La liga venció, ya se usó o no existe. */\n get isGone() {\n return this.status === API_ERROR_STATUS.gone;\n }\n\n /** Errores de un formulario: los mensajes por campo van en problem.errors (fieldErrorsOf). */\n get isValidation() {\n return this.status === API_ERROR_STATUS.validation;\n }\n}\n"],"names":[],"mappings":";AAcY,MAAC,mBAAmB,OAAO,OAAO;AAAA;AAAA,EAE1C,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,UAAU;AAAA;AAAA,EAEV,UAAU;AAAA;AAAA,EAEV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,iBAAiB;AACrB,CAAC;AAEM,MAAM,iBAAiB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQhC,YAAY,EAAC,QAAQ,UAAU,MAAM,qBAAqB,MAAM,oBAAoB,KAAI,GAAG;AACvF,UAAM,eAAe,SAAS,QAAQ,EAAC,mBAAkB,CAAC,CAAC;AAC3D,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,UAAU,WAAW,CAAA;AAC1B,SAAK,OAAO,SAAS,SAAS,WAAW,iBAAiB,UAAU,YAAY;AAChF,SAAK,QAAQ,aAAa,SAAS,QAAQ,EAAC,mBAAkB,CAAC;AAE/D,SAAK,YAAY,SAAS,cAAc;AACxC,SAAK,oBAAoB;AAAA,EAC7B;AAAA;AAAA,EAGA,IAAI,YAAY;AACZ,WAAO,KAAK,WAAW,iBAAiB;AAAA,EAC5C;AAAA;AAAA,EAGA,IAAI,oBAAoB;AACpB,WAAO,KAAK,WAAW,iBAAiB;AAAA,EAC5C;AAAA;AAAA,EAGA,IAAI,aAAa;AACb,WAAO,KAAK,WAAW,iBAAiB;AAAA,EAC5C;AAAA;AAAA,EAGA,IAAI,SAAS;AACT,WAAO,KAAK,WAAW,iBAAiB;AAAA,EAC5C;AAAA;AAAA,EAGA,IAAI,eAAe;AACf,WAAO,KAAK,WAAW,iBAAiB;AAAA,EAC5C;AACJ;"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { ApiError, API_ERROR_STATUS } from "./ApiError.js";
|
|
2
|
+
import { fileNameFromContentDisposition, XLSX_CONTENT_TYPE, isCompleteZip } from "../files.js";
|
|
3
|
+
import { CSRF_TOKEN_MISMATCH_STATUS } from "../laravel/csrfRetry.js";
|
|
4
|
+
import { createLogger } from "../observability/logger.js";
|
|
5
|
+
import { reportPublishedBuild } from "../observability/publishedBuild.js";
|
|
6
|
+
import { toolkitSettings, DEFAULT_LANGUAGE } from "../toolkit/toolkitSettings.js";
|
|
7
|
+
const log = createLogger("api");
|
|
8
|
+
const API_RESPONSE_PARSE = Object.freeze({ json: "json", blob: "blob", response: "response" });
|
|
9
|
+
const DEFAULT_TIMEOUT_MILLISECONDS = 6e4;
|
|
10
|
+
const NO_TIMEOUT = 0;
|
|
11
|
+
const DEFAULT_PUBLISHED_BUILD_HEADER = "X-Frontend-Build";
|
|
12
|
+
const NO_CONTENT_STATUS = 204;
|
|
13
|
+
const SERVER_ERROR_STATUS = 500;
|
|
14
|
+
function apiUrlOf(baseUrl, path, params) {
|
|
15
|
+
const url = /^https?:/i.test(path) ? path : `${baseUrl}${path}`;
|
|
16
|
+
const query = new URLSearchParams();
|
|
17
|
+
for (const [name, value] of Object.entries(params ?? {})) {
|
|
18
|
+
for (const item of [].concat(value)) {
|
|
19
|
+
if (item !== void 0 && item !== null) {
|
|
20
|
+
query.append(name, String(item));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const queryText = query.toString();
|
|
25
|
+
if (!queryText) {
|
|
26
|
+
return url;
|
|
27
|
+
}
|
|
28
|
+
return `${url}${url.includes("?") ? "&" : "?"}${queryText}`;
|
|
29
|
+
}
|
|
30
|
+
function isRawBody(body) {
|
|
31
|
+
return typeof FormData !== "undefined" && body instanceof FormData || typeof Blob !== "undefined" && body instanceof Blob || body instanceof URLSearchParams || body instanceof ArrayBuffer;
|
|
32
|
+
}
|
|
33
|
+
function readCookie(cookieName) {
|
|
34
|
+
if (typeof document === "undefined") {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const prefix = `${cookieName}=`;
|
|
38
|
+
const cookie = document.cookie.split(";").map((part) => part.trim()).find((part) => part.startsWith(prefix));
|
|
39
|
+
return cookie ? decodeURIComponent(cookie.slice(prefix.length)) : null;
|
|
40
|
+
}
|
|
41
|
+
function isSameOrigin(url) {
|
|
42
|
+
if (typeof window === "undefined" || !/^https?:/i.test(url)) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return new URL(url).origin === window.location.origin;
|
|
46
|
+
}
|
|
47
|
+
function retryAfterSecondsOf(retryAfterHeader) {
|
|
48
|
+
if (!retryAfterHeader) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
if (/^\d+$/.test(retryAfterHeader.trim())) {
|
|
52
|
+
return Number(retryAfterHeader.trim());
|
|
53
|
+
}
|
|
54
|
+
const retryAt = Date.parse(retryAfterHeader);
|
|
55
|
+
return Number.isNaN(retryAt) ? null : Math.max(0, Math.ceil((retryAt - Date.now()) / 1e3));
|
|
56
|
+
}
|
|
57
|
+
function toProblemOrNull(toProblem, body, response) {
|
|
58
|
+
const problem = body === null ? null : toProblem(body, response);
|
|
59
|
+
return problem && typeof problem === "object" && !Array.isArray(problem) ? problem : null;
|
|
60
|
+
}
|
|
61
|
+
async function readProblem(response) {
|
|
62
|
+
try {
|
|
63
|
+
const body = JSON.parse(await response.text());
|
|
64
|
+
return body && typeof body === "object" && !Array.isArray(body) ? body : null;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function combinedSignalOf(signal, timeoutMilliseconds) {
|
|
70
|
+
const signals = [signal, timeoutMilliseconds > 0 ? AbortSignal.timeout(timeoutMilliseconds) : null].filter(Boolean);
|
|
71
|
+
if (signals.length < 2) {
|
|
72
|
+
return signals[0];
|
|
73
|
+
}
|
|
74
|
+
return AbortSignal.any(signals);
|
|
75
|
+
}
|
|
76
|
+
async function readBlobWithProgress(response, onDownloadProgress) {
|
|
77
|
+
if (!onDownloadProgress || !response.body) {
|
|
78
|
+
return response.blob();
|
|
79
|
+
}
|
|
80
|
+
const total = Number(response.headers.get("content-length")) || null;
|
|
81
|
+
const reader = response.body.getReader();
|
|
82
|
+
const chunks = [];
|
|
83
|
+
let loaded = 0;
|
|
84
|
+
for (let part = await reader.read(); !part.done; part = await reader.read()) {
|
|
85
|
+
chunks.push(part.value);
|
|
86
|
+
loaded += part.value.byteLength;
|
|
87
|
+
onDownloadProgress({ loaded, total });
|
|
88
|
+
}
|
|
89
|
+
return new Blob(chunks, { type: response.headers.get("content-type") ?? "" });
|
|
90
|
+
}
|
|
91
|
+
function createApiClient({
|
|
92
|
+
baseUrl = "",
|
|
93
|
+
credentials = "same-origin",
|
|
94
|
+
getToken,
|
|
95
|
+
headers: commonHeaders = {},
|
|
96
|
+
publishedBuildHeader = DEFAULT_PUBLISHED_BUILD_HEADER,
|
|
97
|
+
csrf = null,
|
|
98
|
+
timeoutMilliseconds: defaultTimeoutMilliseconds = DEFAULT_TIMEOUT_MILLISECONDS,
|
|
99
|
+
onUnauthenticated,
|
|
100
|
+
onRequest,
|
|
101
|
+
onResponse,
|
|
102
|
+
onError,
|
|
103
|
+
toProblem = (body) => body,
|
|
104
|
+
mapResponse = (body) => body,
|
|
105
|
+
fetch: fetchImplementation
|
|
106
|
+
} = {}) {
|
|
107
|
+
const notify = (eventName, handler, ...eventArguments) => {
|
|
108
|
+
try {
|
|
109
|
+
handler?.(...eventArguments);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
log.error(`el evento ${eventName} del proyecto tronó`, { message: error?.message });
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const fetchOf = () => fetchImplementation ?? globalThis.fetch;
|
|
115
|
+
const csrfCookieName = csrf?.cookieName ?? "XSRF-TOKEN";
|
|
116
|
+
const csrfHeaderName = csrf?.headerName ?? "X-XSRF-TOKEN";
|
|
117
|
+
const headersOf = (url, body, extraHeaders) => {
|
|
118
|
+
const headers = {
|
|
119
|
+
Accept: "application/json",
|
|
120
|
+
"Accept-Language": toolkitSettings().language ?? DEFAULT_LANGUAGE,
|
|
121
|
+
...commonHeaders,
|
|
122
|
+
...extraHeaders
|
|
123
|
+
};
|
|
124
|
+
if (body !== void 0 && !isRawBody(body)) {
|
|
125
|
+
headers["Content-Type"] = "application/json";
|
|
126
|
+
}
|
|
127
|
+
const token = getToken?.();
|
|
128
|
+
if (token) {
|
|
129
|
+
headers.Authorization = `Bearer ${token}`;
|
|
130
|
+
}
|
|
131
|
+
const csrfToken = csrf && isSameOrigin(url) ? readCookie(csrfCookieName) : null;
|
|
132
|
+
if (csrfToken) {
|
|
133
|
+
headers[csrfHeaderName] = csrfToken;
|
|
134
|
+
}
|
|
135
|
+
return headers;
|
|
136
|
+
};
|
|
137
|
+
const send = async (method, url, { body, signal, headers, timeoutMilliseconds }) => {
|
|
138
|
+
const finalHeaders = headersOf(url, body, headers);
|
|
139
|
+
try {
|
|
140
|
+
return await fetchOf()(url, {
|
|
141
|
+
method,
|
|
142
|
+
headers: finalHeaders,
|
|
143
|
+
body: body === void 0 || isRawBody(body) ? body : JSON.stringify(body),
|
|
144
|
+
credentials,
|
|
145
|
+
signal: combinedSignalOf(signal, timeoutMilliseconds)
|
|
146
|
+
});
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (signal?.aborted) {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
const reason = error?.name === "TimeoutError" ? "se acabó el tiempo" : "la petición no llegó al servidor";
|
|
152
|
+
log.error(reason, { method, url, cause: error?.name });
|
|
153
|
+
throw new ApiError({ status: API_ERROR_STATUS.offline });
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const request = async (method, path, options = {}) => {
|
|
157
|
+
const url = apiUrlOf(baseUrl, path, options.params);
|
|
158
|
+
try {
|
|
159
|
+
return await requestOnce(method, url, options);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (error instanceof ApiError) {
|
|
162
|
+
notify("onError", onError, error, { method, url });
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const requestOnce = async (method, url, {
|
|
168
|
+
body,
|
|
169
|
+
signal,
|
|
170
|
+
headers,
|
|
171
|
+
parse = API_RESPONSE_PARSE.json,
|
|
172
|
+
skipUnauthenticatedHandler = false,
|
|
173
|
+
timeoutMilliseconds = defaultTimeoutMilliseconds
|
|
174
|
+
} = {}) => {
|
|
175
|
+
notify("onRequest", onRequest, { method, url });
|
|
176
|
+
const startedAt = Date.now();
|
|
177
|
+
let response = await send(method, url, { body, signal, headers, timeoutMilliseconds });
|
|
178
|
+
if (response.status === CSRF_TOKEN_MISMATCH_STATUS && csrf?.refreshPath) {
|
|
179
|
+
log.info("token CSRF vencido: se renueva y se reintenta", { method, url });
|
|
180
|
+
await send("GET", apiUrlOf(baseUrl, csrf.refreshPath), { signal, timeoutMilliseconds });
|
|
181
|
+
response = await send(method, url, { body, signal, headers, timeoutMilliseconds });
|
|
182
|
+
}
|
|
183
|
+
notify("onResponse", onResponse, { method, url, status: response.status, durationMilliseconds: Date.now() - startedAt });
|
|
184
|
+
if (publishedBuildHeader) {
|
|
185
|
+
reportPublishedBuild(response.headers.get(publishedBuildHeader));
|
|
186
|
+
}
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
const problem = toProblemOrNull(toProblem, await readProblem(response), response);
|
|
189
|
+
const requestedLanguage = headersOf(url, void 0, headers)["Accept-Language"];
|
|
190
|
+
const responseLanguage = response.headers.get("content-language");
|
|
191
|
+
const apiError = new ApiError({
|
|
192
|
+
status: response.status,
|
|
193
|
+
problem,
|
|
194
|
+
translatedByServer: !responseLanguage || responseLanguage.startsWith(requestedLanguage),
|
|
195
|
+
retryAfterSeconds: retryAfterSecondsOf(response.headers.get("retry-after"))
|
|
196
|
+
});
|
|
197
|
+
log[response.status >= SERVER_ERROR_STATUS ? "error" : "debug"](`${method} ${url} → ${response.status}`, {
|
|
198
|
+
code: apiError.code,
|
|
199
|
+
requestId: apiError.requestId ?? response.headers.get("x-request-id")
|
|
200
|
+
});
|
|
201
|
+
if (apiError.isUnauthenticated && !skipUnauthenticatedHandler) {
|
|
202
|
+
onUnauthenticated?.(apiError);
|
|
203
|
+
}
|
|
204
|
+
throw apiError;
|
|
205
|
+
}
|
|
206
|
+
if (parse === API_RESPONSE_PARSE.response) {
|
|
207
|
+
return response;
|
|
208
|
+
}
|
|
209
|
+
if (parse === API_RESPONSE_PARSE.blob) {
|
|
210
|
+
return response.blob();
|
|
211
|
+
}
|
|
212
|
+
if (response.status === NO_CONTENT_STATUS) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const text = await response.text();
|
|
216
|
+
if (!text) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
let json;
|
|
220
|
+
try {
|
|
221
|
+
json = JSON.parse(text);
|
|
222
|
+
} catch {
|
|
223
|
+
log.error(`${method} ${url} respondió algo que no es JSON`, { contentType: response.headers.get("content-type") });
|
|
224
|
+
throw new ApiError({ status: SERVER_ERROR_STATUS });
|
|
225
|
+
}
|
|
226
|
+
return mapResponse(json, { method, url });
|
|
227
|
+
};
|
|
228
|
+
const download = async (path, { params, signal, onDownloadProgress, fallbackFileName = "descarga", timeoutMilliseconds = NO_TIMEOUT } = {}) => {
|
|
229
|
+
const response = await request("GET", path, { params, signal, parse: API_RESPONSE_PARSE.response, timeoutMilliseconds });
|
|
230
|
+
const blob = await readBlobWithProgress(response, onDownloadProgress);
|
|
231
|
+
const fileName = fileNameFromContentDisposition(response.headers.get("content-disposition"), fallbackFileName);
|
|
232
|
+
const contentType = String(response.headers.get("content-type") ?? "").split(";")[0].trim();
|
|
233
|
+
if (contentType === XLSX_CONTENT_TYPE && !await isCompleteZip(blob)) {
|
|
234
|
+
const requestId = response.headers.get("x-request-id");
|
|
235
|
+
log.error(`GET ${path} → el Excel llegó incompleto: el servidor falló a media escritura`, { requestId, fileName });
|
|
236
|
+
throw new ApiError({ status: SERVER_ERROR_STATUS, problem: { request_id: requestId } });
|
|
237
|
+
}
|
|
238
|
+
return { blob, fileName };
|
|
239
|
+
};
|
|
240
|
+
return {
|
|
241
|
+
request,
|
|
242
|
+
get: (path, options) => request("GET", path, options),
|
|
243
|
+
post: (path, body, options) => request("POST", path, { ...options, body }),
|
|
244
|
+
put: (path, body, options) => request("PUT", path, { ...options, body }),
|
|
245
|
+
patch: (path, body, options) => request("PATCH", path, { ...options, body }),
|
|
246
|
+
delete: (path, options) => request("DELETE", path, options),
|
|
247
|
+
download
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
export {
|
|
251
|
+
API_RESPONSE_PARSE,
|
|
252
|
+
apiUrlOf,
|
|
253
|
+
createApiClient,
|
|
254
|
+
retryAfterSecondsOf
|
|
255
|
+
};
|
|
256
|
+
//# sourceMappingURL=createApiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createApiClient.js","sources":["../../src/api/createApiClient.js"],"sourcesContent":["// La petición de la casa: TODO lo que habla con el servidor pasa por un cliente armado aquí, con fetch del navegador (sin\n// axios ni otra librería). Lo que resuelve UNA vez y no en cada pantalla:\n// - Accept-Language con el idioma vigente de ToolkitProvider en CADA petición: el servidor responde title y detail ya\n// traducidos. Cambiar el idioma aplica a la siguiente petición sin recargar.\n// - errores como ApiError (ApiError.js): el problema RFC 9457 del servidor con el mensaje ya traducido; si la\n// respuesta llegó en otro idioma (un error que armó nginx), el texto genérico del paquete. Sin red o se acabó el\n// tiempo: un ApiError con status 0, la misma forma, para que la pantalla no tenga dos formas de error.\n// - cancelar NO es un error: el AbortError se relanza intacto (quien canceló ya sabe por qué).\n// - 401 (la sesión se venció a media consulta): avisa a onUnauthenticated, que normalmente lleva a iniciar sesión. Una\n// petición que espera el 401 (preguntar si hay sesión al arrancar, el login) pasa skipUnauthenticatedHandler.\n// - el aviso «Hay una versión nueva»: cada respuesta trae en un header qué compilación del front está publicada y se\n// le entrega a reportPublishedBuild.\n// - Laravel (Sanctum): con csrf, manda la cookie XSRF-TOKEN en su header (solo al mismo origen) y ante un 419 pide una\n// cookie nueva y repite la petición UNA vez.\n// - cuerpo objeto → JSON; FormData, Blob y URLSearchParams van tal cual (el navegador pone su boundary).\n// - descargas: el Blob y el nombre que mandó el servidor, con avance; un Excel que llegó cortado (el servidor falló a\n// media escritura después de responder 200) no se entrega.\n// - eventos hacia afuera, para lo que cada proyecto haga a su manera: onRequest (sale), onResponse (llegó, con su status\n// y cuánto tardó) y onError (CADA error en un solo lugar: Sentry, un aviso propio, una métrica). Cancelar no es error.\n// Si un evento del proyecto truena, la petición sigue y se anota en el registro.\n// - un backend que ya existe y contesta a su manera, sin cambiarlo: toProblem convierte su error a la forma RFC 9457\n// (Laravel manda {message, errors}) y mapResponse desenvuelve sus respuestas buenas ({data: …}).\n//\n// const api = createApiClient({baseUrl: '/api/v1', onUnauthenticated: () => navigate('/sign-in')});\n// const orders = await api.get('/orders', {params: {page: 2}, signal});\n// await api.post('/orders', {customerId: 7});\n//\n// Se arma uno por proyecto (en su core) y las pantallas lo usan desde su *Api.js.\n//\n// Funciones puras, no renderizan: function (regla de la casa).\nimport {ApiError, API_ERROR_STATUS} from '@/api/ApiError.js';\nimport {XLSX_CONTENT_TYPE, fileNameFromContentDisposition, isCompleteZip} from '@/files.js';\nimport {CSRF_TOKEN_MISMATCH_STATUS} from '@/laravel/csrfRetry.js';\nimport {createLogger} from '@/observability/logger.js';\nimport {reportPublishedBuild} from '@/observability/publishedBuild.js';\nimport {DEFAULT_LANGUAGE, toolkitSettings} from '@/toolkit/toolkitSettings.js';\n\nconst log = createLogger('api');\n\n/** Cómo se lee una respuesta que salió bien. */\nexport const API_RESPONSE_PARSE = Object.freeze({json: 'json', blob: 'blob', response: 'response'});\n\n// Las consultas se cortan a los 60 s; las descargas van sin límite (0): el servidor arma el archivo mientras lo manda y\n// uno grande no cabe en 60 s. No se queda colgada: se cancela desde el panel de descargas.\nconst DEFAULT_TIMEOUT_MILLISECONDS = 60_000;\nconst NO_TIMEOUT = 0;\nconst DEFAULT_PUBLISHED_BUILD_HEADER = 'X-Frontend-Build';\nconst NO_CONTENT_STATUS = 204;\nconst SERVER_ERROR_STATUS = 500;\n\n/**\n * La dirección completa: la base del cliente más el camino, con los parámetros. Un camino que ya trae http(s) va tal cual.\n * Los parámetros vacíos (undefined, null) no viajan; una lista viaja repetida (estado=a&estado=b).\n *\n * @param {string} baseUrl\n * @param {string} path\n * @param {Record<string, unknown>} [params]\n * @returns {string}\n */\nexport function apiUrlOf(baseUrl, path, params) {\n const url = /^https?:/i.test(path) ? path : `${baseUrl}${path}`;\n const query = new URLSearchParams();\n for (const [name, value] of Object.entries(params ?? {})) {\n for (const item of [].concat(value)) {\n if (item !== undefined && item !== null) {\n query.append(name, String(item));\n }\n }\n }\n const queryText = query.toString();\n if (!queryText) {\n return url;\n }\n return `${url}${url.includes('?') ? '&' : '?'}${queryText}`;\n}\n\n/**\n * ¿El cuerpo va tal cual? FormData (archivos), Blob y URLSearchParams los arma el navegador con su propio tipo.\n *\n * @param {unknown} body\n * @returns {boolean}\n */\nfunction isRawBody(body) {\n return (typeof FormData !== 'undefined' && body instanceof FormData)\n || (typeof Blob !== 'undefined' && body instanceof Blob)\n || body instanceof URLSearchParams\n || body instanceof ArrayBuffer;\n}\n\n/**\n * El valor de una cookie del navegador (la XSRF-TOKEN de Laravel), o null.\n *\n * @param {string} cookieName\n * @returns {string|null}\n */\nfunction readCookie(cookieName) {\n if (typeof document === 'undefined') {\n return null;\n }\n const prefix = `${cookieName}=`;\n const cookie = document.cookie.split(';').map((part) => part.trim()).find((part) => part.startsWith(prefix));\n return cookie ? decodeURIComponent(cookie.slice(prefix.length)) : null;\n}\n\n/**\n * ¿La dirección es del mismo origen que la página? El token CSRF solo viaja al servidor propio: mandarlo a otro dominio\n * se lo regalaría.\n *\n * @param {string} url\n * @returns {boolean}\n */\nfunction isSameOrigin(url) {\n if (typeof window === 'undefined' || !/^https?:/i.test(url)) {\n return true;\n }\n return new URL(url).origin === window.location.origin;\n}\n\n/**\n * Retry-After en segundos: el estándar admite segundos o una fecha HTTP.\n *\n * @param {string|null} retryAfterHeader\n * @returns {number|null}\n */\nexport function retryAfterSecondsOf(retryAfterHeader) {\n if (!retryAfterHeader) {\n return null;\n }\n if (/^\\d+$/.test(retryAfterHeader.trim())) {\n return Number(retryAfterHeader.trim());\n }\n const retryAt = Date.parse(retryAfterHeader);\n return Number.isNaN(retryAt) ? null : Math.max(0, Math.ceil((retryAt - Date.now()) / 1000));\n}\n\n/**\n * El cuerpo RFC 9457 de una respuesta de error, o null si no es JSON (un 502 del proxy en HTML).\n *\n * @param {Response} response\n * @returns {Promise<object|null>}\n */\n/**\n * El problema RFC 9457 del cuerpo de error, pasado por el adaptador del proyecto (toProblem). Lo que no sea un objeto\n * cuenta como sin problema (se usa el texto genérico del paquete).\n *\n * @param {(body: any, response: Response) => any} toProblem\n * @param {object|null} body\n * @param {Response} response\n * @returns {object|null}\n */\nfunction toProblemOrNull(toProblem, body, response) {\n const problem = body === null ? null : toProblem(body, response);\n return problem && typeof problem === 'object' && !Array.isArray(problem) ? problem : null;\n}\n\nasync function readProblem(response) {\n try {\n const body = JSON.parse(await response.text());\n return body && typeof body === 'object' && !Array.isArray(body) ? body : null;\n } catch {\n return null;\n }\n}\n\n/**\n * La señal de la petición: la de quien la pidió (para cancelar) y la del tiempo máximo, juntas.\n *\n * @param {AbortSignal|undefined} signal\n * @param {number} timeoutMilliseconds 0 = sin límite\n * @returns {AbortSignal|undefined}\n */\nfunction combinedSignalOf(signal, timeoutMilliseconds) {\n const signals = [signal, timeoutMilliseconds > 0 ? AbortSignal.timeout(timeoutMilliseconds) : null].filter(Boolean);\n if (signals.length < 2) {\n return signals[0];\n }\n return AbortSignal.any(signals);\n}\n\n/**\n * Lee el cuerpo de una descarga avisando cuánto lleva. total viene en null cuando el servidor arma el archivo al vuelo\n * (sin Content-Length).\n *\n * @param {Response} response\n * @param {((progress: {loaded: number, total: number|null}) => void)|undefined} onDownloadProgress\n * @returns {Promise<Blob>}\n */\nasync function readBlobWithProgress(response, onDownloadProgress) {\n if (!onDownloadProgress || !response.body) {\n return response.blob();\n }\n const total = Number(response.headers.get('content-length')) || null;\n const reader = response.body.getReader();\n const chunks = [];\n let loaded = 0;\n for (let part = await reader.read(); !part.done; part = await reader.read()) {\n chunks.push(part.value);\n loaded += part.value.byteLength;\n onDownloadProgress({loaded, total});\n }\n return new Blob(chunks, {type: response.headers.get('content-type') ?? ''});\n}\n\n/**\n * Lo que acepta cada petición.\n *\n * @typedef {object} ApiRequestOptions\n * @property {unknown} [body] objeto → JSON; FormData, Blob o URLSearchParams tal cual\n * @property {Record<string, unknown>} [params] los de la dirección (?page=2)\n * @property {AbortSignal} [signal] para cancelar\n * @property {Record<string, string>} [headers]\n * @property {'json'|'blob'|'response'} [parse] cómo se lee la respuesta (API_RESPONSE_PARSE); por omisión JSON\n * @property {boolean} [skipUnauthenticatedHandler] un 401 que se espera (¿hay sesión?, el login)\n * @property {number} [timeoutMilliseconds] el de esta petición\n */\n\n/**\n * Lo que acepta una descarga.\n *\n * @typedef {object} ApiDownloadOptions\n * @property {Record<string, unknown>} [params]\n * @property {AbortSignal} [signal]\n * @property {(progress: {loaded: number, total: number|null}) => void} [onDownloadProgress]\n * @property {string} [fallbackFileName] si el servidor no manda el nombre\n * @property {number} [timeoutMilliseconds] por omisión sin límite\n */\n\n/**\n * El cliente del proyecto: cada método regresa el JSON de la respuesta (null si vino vacía) o truena con un ApiError.\n *\n * @typedef {object} ApiClient\n * @property {(method: string, path: string, options?: ApiRequestOptions) => Promise<any>} request\n * @property {(path: string, options?: ApiRequestOptions) => Promise<any>} get\n * @property {(path: string, body?: unknown, options?: ApiRequestOptions) => Promise<any>} post\n * @property {(path: string, body?: unknown, options?: ApiRequestOptions) => Promise<any>} put\n * @property {(path: string, body?: unknown, options?: ApiRequestOptions) => Promise<any>} patch\n * @property {(path: string, options?: ApiRequestOptions) => Promise<any>} delete\n * @property {(path: string, options?: ApiDownloadOptions) => Promise<{blob: Blob, fileName: string}>} download\n */\n\n/**\n * Arma el cliente del proyecto.\n *\n * @param {object} [options]\n * @param {string} [options.baseUrl] lo que va antes de cada camino, p. ej. '/api/v1'\n * @param {RequestCredentials} [options.credentials] 'same-origin' (por omisión, la cookie de sesión del mismo dominio) o\n * 'include' (un API en otro dominio con cookies)\n * @param {() => string|null|undefined} [options.getToken] con él cada petición lleva Authorization: Bearer; sin token, va\n * sin el header (el servidor responde 401)\n * @param {Record<string, string>} [options.headers] los que van en todas las peticiones\n * @param {string|null} [options.publishedBuildHeader] el header con la compilación publicada; null para no leerlo\n * @param {{cookieName?: string, headerName?: string, refreshPath?: string}|null} [options.csrf] Laravel Sanctum:\n * {refreshPath: '/auth/csrf-token'}; por omisión la cookie XSRF-TOKEN y el header X-XSRF-TOKEN\n * @param {number} [options.timeoutMilliseconds] el tiempo máximo de una consulta (0 = sin límite); por omisión 60 s\n * @param {(error: ApiError) => void} [options.onUnauthenticated] qué hacer con un 401 (normalmente ir a iniciar sesión)\n * @param {(request: {method: string, url: string}) => void} [options.onRequest] cada petición, al salir\n * @param {(response: {method: string, url: string, status: number, durationMilliseconds: number}) => void} [options.onResponse]\n * cada respuesta, buena o mala, al llegar\n * @param {(error: ApiError, request: {method: string, url: string}) => void} [options.onError] cada error (sin red, 4xx, 5xx,\n * una respuesta que no es JSON), en un solo lugar: Sentry, un aviso propio. Cancelar no es error\n * @param {(body: any, response: Response) => object|null} [options.toProblem] el error de un backend que no contesta en\n * RFC 9457, a esa forma: (body) => ({title: body.message, errors: body.errors}). Por omisión el cuerpo tal cual\n * @param {(body: any, request: {method: string, url: string}) => any} [options.mapResponse] la respuesta buena de un backend\n * que la envuelve: (body) => body.data. Por omisión tal cual\n * @param {typeof fetch} [options.fetch] para un servidor de mentira o para las pruebas; por omisión el del navegador\n * @returns {ApiClient}\n */\nexport function createApiClient({\n baseUrl = '',\n credentials = 'same-origin',\n getToken,\n headers: commonHeaders = {},\n publishedBuildHeader = DEFAULT_PUBLISHED_BUILD_HEADER,\n csrf = null,\n timeoutMilliseconds: defaultTimeoutMilliseconds = DEFAULT_TIMEOUT_MILLISECONDS,\n onUnauthenticated,\n onRequest,\n onResponse,\n onError,\n toProblem = (body) => body,\n mapResponse = (body) => body,\n fetch: fetchImplementation,\n} = {}) {\n // un evento del proyecto que truena no tumba la petición: se anota y se sigue (nunca en silencio)\n const notify = (eventName, handler, ...eventArguments) => {\n try {\n handler?.(...eventArguments);\n } catch (error) {\n log.error(`el evento ${eventName} del proyecto tronó`, {message: error?.message});\n }\n };\n // OJO: se lee al pedir, no al armar el cliente: así un servidor de mentira que se conecta después también sirve\n const fetchOf = () => fetchImplementation ?? globalThis.fetch;\n const csrfCookieName = csrf?.cookieName ?? 'XSRF-TOKEN';\n const csrfHeaderName = csrf?.headerName ?? 'X-XSRF-TOKEN';\n\n /** Los headers de una petición: los comunes, el idioma vigente, el token y el CSRF. */\n const headersOf = (url, body, extraHeaders) => {\n const headers = {\n Accept: 'application/json',\n 'Accept-Language': toolkitSettings().language ?? DEFAULT_LANGUAGE,\n ...commonHeaders,\n ...extraHeaders,\n };\n if (body !== undefined && !isRawBody(body)) {\n headers['Content-Type'] = 'application/json';\n }\n const token = getToken?.();\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n const csrfToken = csrf && isSameOrigin(url) ? readCookie(csrfCookieName) : null;\n if (csrfToken) {\n headers[csrfHeaderName] = csrfToken;\n }\n return headers;\n };\n\n /** La petición al servidor, ya con su respuesta o con el ApiError de «sin respuesta». */\n const send = async (method, url, {body, signal, headers, timeoutMilliseconds}) => {\n const finalHeaders = headersOf(url, body, headers);\n try {\n return await fetchOf()(url, {\n method,\n headers: finalHeaders,\n body: body === undefined || isRawBody(body) ? body : JSON.stringify(body),\n credentials,\n signal: combinedSignalOf(signal, timeoutMilliseconds),\n });\n } catch (error) {\n // cancelar no es un error de negocio: quien canceló ya sabe por qué\n if (signal?.aborted) {\n throw error;\n }\n const reason = error?.name === 'TimeoutError' ? 'se acabó el tiempo' : 'la petición no llegó al servidor';\n log.error(reason, {method, url, cause: error?.name});\n throw new ApiError({status: API_ERROR_STATUS.offline});\n }\n };\n\n /**\n * Cualquier petición.\n *\n * @param {string} method 'GET', 'POST', 'PUT', 'PATCH' o 'DELETE'\n * @param {string} path relativo a baseUrl (o completo con http)\n * @param {object} [options]\n * @param {unknown} [options.body] objeto → JSON; FormData, Blob o URLSearchParams tal cual\n * @param {Record<string, unknown>} [options.params] los de la dirección (?page=2)\n * @param {AbortSignal} [options.signal] para cancelar\n * @param {Record<string, string>} [options.headers]\n * @param {'json'|'blob'|'response'} [options.parse] cómo se lee la respuesta (API_RESPONSE_PARSE); por omisión JSON\n * @param {boolean} [options.skipUnauthenticatedHandler] un 401 que se espera (¿hay sesión?, el login)\n * @param {number} [options.timeoutMilliseconds] el de esta petición\n * @returns {Promise<any>} el JSON (null si vino vacío o 204), el Blob o la Response\n */\n const request = async (method, path, options = {}) => {\n const url = apiUrlOf(baseUrl, path, options.params);\n try {\n return await requestOnce(method, url, options);\n } catch (error) {\n // cada error del servidor (o sin red) sale por onError; cancelar no es error\n if (error instanceof ApiError) {\n notify('onError', onError, error, {method, url});\n }\n throw error;\n }\n };\n\n const requestOnce = async (method, url, {\n body, signal, headers, parse = API_RESPONSE_PARSE.json, skipUnauthenticatedHandler = false,\n timeoutMilliseconds = defaultTimeoutMilliseconds,\n } = {}) => {\n notify('onRequest', onRequest, {method, url});\n const startedAt = Date.now();\n let response = await send(method, url, {body, signal, headers, timeoutMilliseconds});\n\n // 419 de Laravel: la cookie CSRF venció; se pide una nueva y se repite la MISMA petición una sola vez\n if (response.status === CSRF_TOKEN_MISMATCH_STATUS && csrf?.refreshPath) {\n log.info('token CSRF vencido: se renueva y se reintenta', {method, url});\n await send('GET', apiUrlOf(baseUrl, csrf.refreshPath), {signal, timeoutMilliseconds});\n response = await send(method, url, {body, signal, headers, timeoutMilliseconds});\n }\n\n notify('onResponse', onResponse, {method, url, status: response.status, durationMilliseconds: Date.now() - startedAt});\n\n // cada respuesta (también las de error) dice qué compilación del front está publicada\n if (publishedBuildHeader) {\n reportPublishedBuild(response.headers.get(publishedBuildHeader));\n }\n\n if (!response.ok) {\n const problem = toProblemOrNull(toProblem, await readProblem(response), response);\n // un error que armó otro (nginx) puede llegar en otro idioma: ahí se usa el texto genérico del paquete\n const requestedLanguage = headersOf(url, undefined, headers)['Accept-Language'];\n const responseLanguage = response.headers.get('content-language');\n const apiError = new ApiError({\n status: response.status,\n problem,\n translatedByServer: !responseLanguage || responseLanguage.startsWith(requestedLanguage),\n retryAfterSeconds: retryAfterSecondsOf(response.headers.get('retry-after')),\n });\n // los 4xx son parte del flujo (un 422 es un formulario, un 401 al arrancar es «sin sesión»); los 5xx no\n log[response.status >= SERVER_ERROR_STATUS ? 'error' : 'debug'](`${method} ${url} → ${response.status}`, {\n code: apiError.code, requestId: apiError.requestId ?? response.headers.get('x-request-id'),\n });\n if (apiError.isUnauthenticated && !skipUnauthenticatedHandler) {\n onUnauthenticated?.(apiError);\n }\n throw apiError;\n }\n\n if (parse === API_RESPONSE_PARSE.response) {\n return response;\n }\n if (parse === API_RESPONSE_PARSE.blob) {\n return response.blob();\n }\n if (response.status === NO_CONTENT_STATUS) {\n return null;\n }\n // un 200 con el cuerpo vacío pasa de verdad; JSON.parse('') tronaría\n const text = await response.text();\n if (!text) {\n return null;\n }\n let json;\n try {\n json = JSON.parse(text);\n } catch {\n // un 200 que no es JSON: casi siempre la página de la app que respondió en lugar del API (el camino está mal)\n log.error(`${method} ${url} respondió algo que no es JSON`, {contentType: response.headers.get('content-type')});\n throw new ApiError({status: SERVER_ERROR_STATUS});\n }\n return mapResponse(json, {method, url});\n };\n\n /**\n * Descarga un archivo: el Blob y el nombre que mandó el servidor, con avance. Un Excel cortado no se entrega.\n *\n * @param {string} path\n * @param {object} [options]\n * @param {Record<string, unknown>} [options.params]\n * @param {AbortSignal} [options.signal]\n * @param {(progress: {loaded: number, total: number|null}) => void} [options.onDownloadProgress]\n * @param {string} [options.fallbackFileName] si el servidor no manda el nombre\n * @param {number} [options.timeoutMilliseconds] por omisión sin límite\n * @returns {Promise<{blob: Blob, fileName: string}>}\n * @throws {ApiError} status 500 si un Excel llegó incompleto\n */\n const download = async (path, {params, signal, onDownloadProgress, fallbackFileName = 'descarga', timeoutMilliseconds = NO_TIMEOUT} = {}) => {\n const response = await request('GET', path, {params, signal, parse: API_RESPONSE_PARSE.response, timeoutMilliseconds});\n const blob = await readBlobWithProgress(response, onDownloadProgress);\n const fileName = fileNameFromContentDisposition(response.headers.get('content-disposition'), fallbackFileName);\n // el tipo puede traer parámetros después del «;» (charset): solo cuenta lo de antes\n const contentType = String(response.headers.get('content-type') ?? '').split(';')[0].trim();\n if (contentType === XLSX_CONTENT_TYPE && !(await isCompleteZip(blob))) {\n const requestId = response.headers.get('x-request-id');\n log.error(`GET ${path} → el Excel llegó incompleto: el servidor falló a media escritura`, {requestId, fileName});\n throw new ApiError({status: SERVER_ERROR_STATUS, problem: {request_id: requestId}});\n }\n return {blob, fileName};\n };\n\n return {\n request,\n get: (path, options) => request('GET', path, options),\n post: (path, body, options) => request('POST', path, {...options, body}),\n put: (path, body, options) => request('PUT', path, {...options, body}),\n patch: (path, body, options) => request('PATCH', path, {...options, body}),\n delete: (path, options) => request('DELETE', path, options),\n download,\n };\n}\n"],"names":[],"mappings":";;;;;;AAqCA,MAAM,MAAM,aAAa,KAAK;AAGlB,MAAC,qBAAqB,OAAO,OAAO,EAAC,MAAM,QAAQ,MAAM,QAAQ,UAAU,WAAU,CAAC;AAIlG,MAAM,+BAA+B;AACrC,MAAM,aAAa;AACnB,MAAM,iCAAiC;AACvC,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;AAWrB,SAAS,SAAS,SAAS,MAAM,QAAQ;AAC5C,QAAM,MAAM,YAAY,KAAK,IAAI,IAAI,OAAO,GAAG,OAAO,GAAG,IAAI;AAC7D,QAAM,QAAQ,IAAI,gBAAe;AACjC,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,UAAU,CAAA,CAAE,GAAG;AACtD,eAAW,QAAQ,CAAA,EAAG,OAAO,KAAK,GAAG;AACjC,UAAI,SAAS,UAAa,SAAS,MAAM;AACrC,cAAM,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA,MACnC;AAAA,IACJ;AAAA,EACJ;AACA,QAAM,YAAY,MAAM,SAAQ;AAChC,MAAI,CAAC,WAAW;AACZ,WAAO;AAAA,EACX;AACA,SAAO,GAAG,GAAG,GAAG,IAAI,SAAS,GAAG,IAAI,MAAM,GAAG,GAAG,SAAS;AAC7D;AAQA,SAAS,UAAU,MAAM;AACrB,SAAQ,OAAO,aAAa,eAAe,gBAAgB,YACnD,OAAO,SAAS,eAAe,gBAAgB,QAChD,gBAAgB,mBAChB,gBAAgB;AAC3B;AAQA,SAAS,WAAW,YAAY;AAC5B,MAAI,OAAO,aAAa,aAAa;AACjC,WAAO;AAAA,EACX;AACA,QAAM,SAAS,GAAG,UAAU;AAC5B,QAAM,SAAS,SAAS,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,KAAK,KAAI,CAAE,EAAE,KAAK,CAAC,SAAS,KAAK,WAAW,MAAM,CAAC;AAC3G,SAAO,SAAS,mBAAmB,OAAO,MAAM,OAAO,MAAM,CAAC,IAAI;AACtE;AASA,SAAS,aAAa,KAAK;AACvB,MAAI,OAAO,WAAW,eAAe,CAAC,YAAY,KAAK,GAAG,GAAG;AACzD,WAAO;AAAA,EACX;AACA,SAAO,IAAI,IAAI,GAAG,EAAE,WAAW,OAAO,SAAS;AACnD;AAQO,SAAS,oBAAoB,kBAAkB;AAClD,MAAI,CAAC,kBAAkB;AACnB,WAAO;AAAA,EACX;AACA,MAAI,QAAQ,KAAK,iBAAiB,KAAI,CAAE,GAAG;AACvC,WAAO,OAAO,iBAAiB,MAAM;AAAA,EACzC;AACA,QAAM,UAAU,KAAK,MAAM,gBAAgB;AAC3C,SAAO,OAAO,MAAM,OAAO,IAAI,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,KAAK,IAAG,KAAM,GAAI,CAAC;AAC9F;AAiBA,SAAS,gBAAgB,WAAW,MAAM,UAAU;AAChD,QAAM,UAAU,SAAS,OAAO,OAAO,UAAU,MAAM,QAAQ;AAC/D,SAAO,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,IAAI,UAAU;AACzF;AAEA,eAAe,YAAY,UAAU;AACjC,MAAI;AACA,UAAM,OAAO,KAAK,MAAM,MAAM,SAAS,KAAI,CAAE;AAC7C,WAAO,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,IAAI,OAAO;AAAA,EAC7E,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AASA,SAAS,iBAAiB,QAAQ,qBAAqB;AACnD,QAAM,UAAU,CAAC,QAAQ,sBAAsB,IAAI,YAAY,QAAQ,mBAAmB,IAAI,IAAI,EAAE,OAAO,OAAO;AAClH,MAAI,QAAQ,SAAS,GAAG;AACpB,WAAO,QAAQ,CAAC;AAAA,EACpB;AACA,SAAO,YAAY,IAAI,OAAO;AAClC;AAUA,eAAe,qBAAqB,UAAU,oBAAoB;AAC9D,MAAI,CAAC,sBAAsB,CAAC,SAAS,MAAM;AACvC,WAAO,SAAS,KAAI;AAAA,EACxB;AACA,QAAM,QAAQ,OAAO,SAAS,QAAQ,IAAI,gBAAgB,CAAC,KAAK;AAChE,QAAM,SAAS,SAAS,KAAK,UAAS;AACtC,QAAM,SAAS,CAAA;AACf,MAAI,SAAS;AACb,WAAS,OAAO,MAAM,OAAO,KAAI,GAAI,CAAC,KAAK,MAAM,OAAO,MAAM,OAAO,KAAI,GAAI;AACzE,WAAO,KAAK,KAAK,KAAK;AACtB,cAAU,KAAK,MAAM;AACrB,uBAAmB,EAAC,QAAQ,MAAK,CAAC;AAAA,EACtC;AACA,SAAO,IAAI,KAAK,QAAQ,EAAC,MAAM,SAAS,QAAQ,IAAI,cAAc,KAAK,GAAE,CAAC;AAC9E;AAkEO,SAAS,gBAAgB;AAAA,EAC5B,UAAU;AAAA,EACV,cAAc;AAAA,EACd;AAAA,EACA,SAAS,gBAAgB,CAAA;AAAA,EACzB,uBAAuB;AAAA,EACvB,OAAO;AAAA,EACP,qBAAqB,6BAA6B;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY,CAAC,SAAS;AAAA,EACtB,cAAc,CAAC,SAAS;AAAA,EACxB,OAAO;AACX,IAAI,IAAI;AAEJ,QAAM,SAAS,CAAC,WAAW,YAAY,mBAAmB;AACtD,QAAI;AACA,gBAAU,GAAG,cAAc;AAAA,IAC/B,SAAS,OAAO;AACZ,UAAI,MAAM,aAAa,SAAS,uBAAuB,EAAC,SAAS,OAAO,QAAO,CAAC;AAAA,IACpF;AAAA,EACJ;AAEA,QAAM,UAAU,MAAM,uBAAuB,WAAW;AACxD,QAAM,iBAAiB,MAAM,cAAc;AAC3C,QAAM,iBAAiB,MAAM,cAAc;AAG3C,QAAM,YAAY,CAAC,KAAK,MAAM,iBAAiB;AAC3C,UAAM,UAAU;AAAA,MACZ,QAAQ;AAAA,MACR,mBAAmB,kBAAkB,YAAY;AAAA,MACjD,GAAG;AAAA,MACH,GAAG;AAAA,IACf;AACQ,QAAI,SAAS,UAAa,CAAC,UAAU,IAAI,GAAG;AACxC,cAAQ,cAAc,IAAI;AAAA,IAC9B;AACA,UAAM,QAAQ,WAAQ;AACtB,QAAI,OAAO;AACP,cAAQ,gBAAgB,UAAU,KAAK;AAAA,IAC3C;AACA,UAAM,YAAY,QAAQ,aAAa,GAAG,IAAI,WAAW,cAAc,IAAI;AAC3E,QAAI,WAAW;AACX,cAAQ,cAAc,IAAI;AAAA,IAC9B;AACA,WAAO;AAAA,EACX;AAGA,QAAM,OAAO,OAAO,QAAQ,KAAK,EAAC,MAAM,QAAQ,SAAS,oBAAmB,MAAM;AAC9E,UAAM,eAAe,UAAU,KAAK,MAAM,OAAO;AACjD,QAAI;AACA,aAAO,MAAM,QAAO,EAAG,KAAK;AAAA,QACxB;AAAA,QACA,SAAS;AAAA,QACT,MAAM,SAAS,UAAa,UAAU,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI;AAAA,QACxE;AAAA,QACA,QAAQ,iBAAiB,QAAQ,mBAAmB;AAAA,MACpE,CAAa;AAAA,IACL,SAAS,OAAO;AAEZ,UAAI,QAAQ,SAAS;AACjB,cAAM;AAAA,MACV;AACA,YAAM,SAAS,OAAO,SAAS,iBAAiB,uBAAuB;AACvE,UAAI,MAAM,QAAQ,EAAC,QAAQ,KAAK,OAAO,OAAO,KAAI,CAAC;AACnD,YAAM,IAAI,SAAS,EAAC,QAAQ,iBAAiB,QAAO,CAAC;AAAA,IACzD;AAAA,EACJ;AAiBA,QAAM,UAAU,OAAO,QAAQ,MAAM,UAAU,CAAA,MAAO;AAClD,UAAM,MAAM,SAAS,SAAS,MAAM,QAAQ,MAAM;AAClD,QAAI;AACA,aAAO,MAAM,YAAY,QAAQ,KAAK,OAAO;AAAA,IACjD,SAAS,OAAO;AAEZ,UAAI,iBAAiB,UAAU;AAC3B,eAAO,WAAW,SAAS,OAAO,EAAC,QAAQ,IAAG,CAAC;AAAA,MACnD;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAEA,QAAM,cAAc,OAAO,QAAQ,KAAK;AAAA,IACpC;AAAA,IAAM;AAAA,IAAQ;AAAA,IAAS,QAAQ,mBAAmB;AAAA,IAAM,6BAA6B;AAAA,IACrF,sBAAsB;AAAA,EAC9B,IAAQ,OAAO;AACP,WAAO,aAAa,WAAW,EAAC,QAAQ,IAAG,CAAC;AAC5C,UAAM,YAAY,KAAK,IAAG;AAC1B,QAAI,WAAW,MAAM,KAAK,QAAQ,KAAK,EAAC,MAAM,QAAQ,SAAS,oBAAmB,CAAC;AAGnF,QAAI,SAAS,WAAW,8BAA8B,MAAM,aAAa;AACrE,UAAI,KAAK,iDAAiD,EAAC,QAAQ,IAAG,CAAC;AACvE,YAAM,KAAK,OAAO,SAAS,SAAS,KAAK,WAAW,GAAG,EAAC,QAAQ,oBAAmB,CAAC;AACpF,iBAAW,MAAM,KAAK,QAAQ,KAAK,EAAC,MAAM,QAAQ,SAAS,oBAAmB,CAAC;AAAA,IACnF;AAEA,WAAO,cAAc,YAAY,EAAC,QAAQ,KAAK,QAAQ,SAAS,QAAQ,sBAAsB,KAAK,IAAG,IAAK,UAAS,CAAC;AAGrH,QAAI,sBAAsB;AACtB,2BAAqB,SAAS,QAAQ,IAAI,oBAAoB,CAAC;AAAA,IACnE;AAEA,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,UAAU,gBAAgB,WAAW,MAAM,YAAY,QAAQ,GAAG,QAAQ;AAEhF,YAAM,oBAAoB,UAAU,KAAK,QAAW,OAAO,EAAE,iBAAiB;AAC9E,YAAM,mBAAmB,SAAS,QAAQ,IAAI,kBAAkB;AAChE,YAAM,WAAW,IAAI,SAAS;AAAA,QAC1B,QAAQ,SAAS;AAAA,QACjB;AAAA,QACA,oBAAoB,CAAC,oBAAoB,iBAAiB,WAAW,iBAAiB;AAAA,QACtF,mBAAmB,oBAAoB,SAAS,QAAQ,IAAI,aAAa,CAAC;AAAA,MAC1F,CAAa;AAED,UAAI,SAAS,UAAU,sBAAsB,UAAU,OAAO,EAAE,GAAG,MAAM,IAAI,GAAG,MAAM,SAAS,MAAM,IAAI;AAAA,QACrG,MAAM,SAAS;AAAA,QAAM,WAAW,SAAS,aAAa,SAAS,QAAQ,IAAI,cAAc;AAAA,MACzG,CAAa;AACD,UAAI,SAAS,qBAAqB,CAAC,4BAA4B;AAC3D,4BAAoB,QAAQ;AAAA,MAChC;AACA,YAAM;AAAA,IACV;AAEA,QAAI,UAAU,mBAAmB,UAAU;AACvC,aAAO;AAAA,IACX;AACA,QAAI,UAAU,mBAAmB,MAAM;AACnC,aAAO,SAAS,KAAI;AAAA,IACxB;AACA,QAAI,SAAS,WAAW,mBAAmB;AACvC,aAAO;AAAA,IACX;AAEA,UAAM,OAAO,MAAM,SAAS,KAAI;AAChC,QAAI,CAAC,MAAM;AACP,aAAO;AAAA,IACX;AACA,QAAI;AACJ,QAAI;AACA,aAAO,KAAK,MAAM,IAAI;AAAA,IAC1B,QAAQ;AAEJ,UAAI,MAAM,GAAG,MAAM,IAAI,GAAG,kCAAkC,EAAC,aAAa,SAAS,QAAQ,IAAI,cAAc,EAAC,CAAC;AAC/G,YAAM,IAAI,SAAS,EAAC,QAAQ,oBAAmB,CAAC;AAAA,IACpD;AACA,WAAO,YAAY,MAAM,EAAC,QAAQ,IAAG,CAAC;AAAA,EAC1C;AAeA,QAAM,WAAW,OAAO,MAAM,EAAC,QAAQ,QAAQ,oBAAoB,mBAAmB,YAAY,sBAAsB,WAAU,IAAI,CAAA,MAAO;AACzI,UAAM,WAAW,MAAM,QAAQ,OAAO,MAAM,EAAC,QAAQ,QAAQ,OAAO,mBAAmB,UAAU,oBAAmB,CAAC;AACrH,UAAM,OAAO,MAAM,qBAAqB,UAAU,kBAAkB;AACpE,UAAM,WAAW,+BAA+B,SAAS,QAAQ,IAAI,qBAAqB,GAAG,gBAAgB;AAE7G,UAAM,cAAc,OAAO,SAAS,QAAQ,IAAI,cAAc,KAAK,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAI;AACzF,QAAI,gBAAgB,qBAAqB,CAAE,MAAM,cAAc,IAAI,GAAI;AACnE,YAAM,YAAY,SAAS,QAAQ,IAAI,cAAc;AACrD,UAAI,MAAM,OAAO,IAAI,qEAAqE,EAAC,WAAW,SAAQ,CAAC;AAC/G,YAAM,IAAI,SAAS,EAAC,QAAQ,qBAAqB,SAAS,EAAC,YAAY,UAAS,EAAC,CAAC;AAAA,IACtF;AACA,WAAO,EAAC,MAAM,SAAQ;AAAA,EAC1B;AAEA,SAAO;AAAA,IACH;AAAA,IACA,KAAK,CAAC,MAAM,YAAY,QAAQ,OAAO,MAAM,OAAO;AAAA,IACpD,MAAM,CAAC,MAAM,MAAM,YAAY,QAAQ,QAAQ,MAAM,EAAC,GAAG,SAAS,KAAI,CAAC;AAAA,IACvE,KAAK,CAAC,MAAM,MAAM,YAAY,QAAQ,OAAO,MAAM,EAAC,GAAG,SAAS,KAAI,CAAC;AAAA,IACrE,OAAO,CAAC,MAAM,MAAM,YAAY,QAAQ,SAAS,MAAM,EAAC,GAAG,SAAS,KAAI,CAAC;AAAA,IACzE,QAAQ,CAAC,MAAM,YAAY,QAAQ,UAAU,MAAM,OAAO;AAAA,IAC1D;AAAA,EACR;AACA;"}
|