Files
Jacky 69cfa82b1d feat: self-signed certificate support (#1655) (#1688)
* feat(cert): add self-signed certificate type and config to model

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): generate self-signed leaf certificates

Add GenerateSelfSigned / SelfSignedOptions plus five new error codes
(50032-50036) and a full TDD test suite covering valid cert output,
multiple key types, empty-SAN rejection, and invalid-IP rejection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): regenerate self-signed certificates with key reuse

Add RegenerateSelfSigned, SelfSignedOptionsFromModel, deriveSelfSignedCommonName,
loadSelfSignedKey, and parsePrivateKeyPEM to support re-issuing self-signed
certificates for the auto-renewal job, reusing the on-disk private key when possible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): add self-signed certificate renewal worker

Add auto-renewal worker for self-signed certificates that mirrors the
ACME renewal logic, using a dedicated shouldRenewSelfSignedCert threshold
function verified with TDD.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cron): schedule self-signed certificate renewal

Register setupSelfSignedCertRenewalJob as a periodic cron job (every
30 minutes) in InitCronJobs, mirroring the existing setupAutoCertJob
pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(api): add self-signed certificate generation endpoints

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): add self-signed certificate frontend API

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): add shared self-signed certificate fields component

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): add self-signed certificate generation modal and list entry

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): support self-signed certificates in the editor

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(site): generate self-signed certificates from the site editor

Extract hasTLSListen/ensureDirective/ensureTLSDirectives into a shared
useTLSDirectives composable, refactor ObtainCert.vue to use it, and add
SelfSignedCert.vue to the site cert tab so users can generate and apply
a self-signed certificate directly from the site editor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(cert): validate self-signed key type and name IP-only renewals

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(cert): apply code-review cleanup

- reuse certcrypto.ParsePEMPrivateKey instead of a hand-rolled PEM
  private-key parser
- stop exporting the unused ensureDirective from useTLSDirectives
- use the AutoCertState enum instead of integer literals in certColumns
- allocate the renewal Logger only when renewal is attempted, avoiding a
  per-tick goroutine and empty-log database write for non-due certificates

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(cert): address PR #1688 review feedback

- clean up the partial certificate directory when the initial write
  fails, not just the database row
- log a warning when the existing self-signed private key cannot be
  reused so operators notice the public-key fingerprint has changed
- defensively copy the model's Domains and IPAddresses slices in
  SelfSignedOptionsFromModel
- require an explicit "Save now" confirmation after generating from the
  site editor, and write the directives into the editor first so the
  user can review the diff before saving

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(cert): harden self-signed certificate lifecycle

Reuse private keys on manual self-signed edits, make certificate writes safer, clean managed self-signed files on delete, and guard renewal against missing config.

* fix(cert): harden self-signed frontend handling

Avoid undefined certificate redirects, rely on payload defaults for self-signed fields, and parse TLS listen directives precisely.

* fix(site): satisfy strict listen regex lint

Escape the IPv6 listen closing bracket explicitly so the strict regexp lint rule accepts TLS listen parsing.

* fix(cert): harden self-signed key handling

Co-authored-by: Jacky <me@jackyu.cn>

* docs(cert): design merging self-signed entry into issue dialog

Spec for collapsing the Certificate list header from three actions to
two by adding a Self-signed option inside the existing Issue Certificate
dialog.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(cert): plan merging self-signed into issue dialog

Step-by-step plan that turns the spec into two scoped commits:
extend DNSIssueCertificate with a self-signed type, then drop the
standalone header button from the certificate list view.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): add self-signed option in issue certificate dialog

Extend the Issue Certificate dialog's Certificate Type select with a
"Self-signed" option that swaps the form body to SelfSignedCertFields
and routes submission through cert.generate_self_signed(). ACME paths
(Wildcard / Custom Domains) are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(cert): drop standalone self-signed button from list header

Certificate creation is now consolidated under the Issue Certificate
dialog (which exposes Self-signed as a Certificate Type option), so
the duplicate header entry, its ref, handler, and modal mount are
removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(cert): design self-signed UX enhancements

Adds a reusable StringListInput, renewal-policy hint in the self-signed
form, and a required Name field (frontend + backend). Builds on the
prior merge spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(cert): plan self-signed UX enhancements

Six-task plan: extract StringListInput, require Name backend + test,
refactor SelfSignedCertFields with renewal hint, hide duplicate alert
in editor, seed/filter payloads with Name validation, and adopt
StringListInput in the ACME Custom Domains branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(ui): add StringListInput component

Reusable multi-row text input with Add/Remove buttons. Used in the
upcoming refactor of Custom Domains and self-signed Domains / IP
Addresses editors so all three share a single editor pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ui): simplify StringListInput model write and add a11y label

Replace the captured-index update closure with v-model:value on
items[index] so input events are guaranteed to write to the array
slot currently bound to the DOM input. Add an aria-label suffix
on the Remove button so screen readers can distinguish rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): require Name when generating self-signed certificates

Adds binding:"required" to SelfSignedCertRequest.Name so an empty name
is rejected at the request boundary, and covers the contract with a
new API-level test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): unify self-signed editor and surface renewal hint

Switch Domains and IP Addresses to the shared StringListInput so all
self-signed field editors match the Custom Domains pattern. Add an
auto-renewal hint (suppressible via hideRenewalNote) and mark Name as
required to match the new backend contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(cert): suppress duplicate renewal alert in cert editor

SelfSignedCertManagement already has its own renewal-status alert;
pass hide-renewal-note to SelfSignedCertFields to avoid showing two
adjacent alerts saying the same thing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cert): seed and filter self-signed payloads, validate Name

StringListInput preserves empty placeholder rows for editing; seed
arrays with [''] in toSelfSignedPayload / emptySelfSignedPayload /
emptyForm so the editor always renders an empty row to type into.

Each submit/save path trims and filters the arrays before sending and
now rejects an empty Name client-side to match the new server contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(cert): make SelfSignedCertPayload.name required

Every factory already seeds name as ''; the optional marker forced
defensive (name ?? '').trim() at three call sites. Align the type
with reality.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(cert): use StringListInput for Custom Domains

Drop the inline multi-row template + add/remove helpers in favour of
the shared StringListInput component, matching the editor used by the
self-signed branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(ui): regenerate components.d.ts for StringListInput

Auto-generated by unplugin-vue-components after the new component
was added under app/src/components/StringListInput/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(cert): render key_type for both legacy and canonical forms

The backend's helper.GetKeyType normalizes key_type to its canonical
form (EC256, RSA2048…) on every write — self-signed generation as well
as the ModifyCert BeforeExecuteHook. The frontend PrivateKeyTypeMask
was keyed only by the legacy form (P256, 2048…), so maskRender returned
"/" for every cert that took a write path through normalization.

Two reported symptoms with the same root cause:
- New self-signed cert always shows "/" in the Key Type column
- Editing any ACME cert (issue #1697) flips its column to "/" after save

Add formatPrivateKeyType / normalizePrivateKeyType helpers that map both
forms to the frontend's legacy key. Use them in the list column renderer
and when loading certs into the self-signed and ACME editor forms so the
ASelect highlights the correct option.

Fixes #1697.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* style(cert): cap self-signed fields width at 600px

The fields stretched full-width inside the certificate editor page; cap
the form at 600px to match AutoCertManagement and keep the editing area
readable. Modal consumers were already bounded by their own width, so
the change is invisible there.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: update translations

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Hintay <hintay@me.com>
2026-05-24 09:22:21 +08:00

292 lines
23 KiB
TypeScript

/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import { GlobalComponents } from 'vue'
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AAlert: typeof import('ant-design-vue/es')['Alert']
AApp: typeof import('ant-design-vue/es')['App']
AAutoComplete: typeof import('ant-design-vue/es')['AutoComplete']
AAvatar: typeof import('ant-design-vue/es')['Avatar']
ABadge: typeof import('ant-design-vue/es')['Badge']
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col']
ACollapse: typeof import('ant-design-vue/es')['Collapse']
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
AComment: typeof import('ant-design-vue/es')['Comment']
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
AInputGroup: typeof import('ant-design-vue/es')['InputGroup']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
ALayout: typeof import('ant-design-vue/es')['Layout']
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
ALayoutFooter: typeof import('ant-design-vue/es')['LayoutFooter']
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
AList: typeof import('ant-design-vue/es')['List']
AListItem: typeof import('ant-design-vue/es')['ListItem']
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
APagination: typeof import('ant-design-vue/es')['Pagination']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
APopover: typeof import('ant-design-vue/es')['Popover']
AppProviderAppProvider: typeof import('./src/components/AppProvider/AppProvider.vue')['default']
AProgress: typeof import('ant-design-vue/es')['Progress']
AQrcode: typeof import('ant-design-vue/es')['QRCode']
ARadio: typeof import('ant-design-vue/es')['Radio']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARangePicker: typeof import('ant-design-vue/es/date-picker/dayjs')['RangePicker']
AResult: typeof import('ant-design-vue/es')['Result']
ARow: typeof import('ant-design-vue/es')['Row']
ASegmented: typeof import('ant-design-vue/es')['Segmented']
ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin']
AStatistic: typeof import('ant-design-vue/es')['Statistic']
AStep: typeof import('ant-design-vue/es')['Step']
ASteps: typeof import('ant-design-vue/es')['Steps']
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table']
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATypographyParagraph: typeof import('ant-design-vue/es')['TypographyParagraph']
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
ATypographyTitle: typeof import('ant-design-vue/es')['TypographyTitle']
AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
AutoCertFormAutoCertForm: typeof import('./src/components/AutoCertForm/AutoCertForm.vue')['default']
AutoCertFormDNSChallenge: typeof import('./src/components/AutoCertForm/DNSChallenge.vue')['default']
BaseEditorBaseEditor: typeof import('./src/components/BaseEditor/BaseEditor.vue')['default']
BreadcrumbBreadcrumb: typeof import('./src/components/Breadcrumb/Breadcrumb.vue')['default']
CertInfoCertInfo: typeof import('./src/components/CertInfo/CertInfo.vue')['default']
ChartAreaChart: typeof import('./src/components/Chart/AreaChart.vue')['default']
ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default']
ChartUsageProgressLine: typeof import('./src/components/Chart/UsageProgressLine.vue')['default']
CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
ConfigHistoryConfigHistory: typeof import('./src/components/ConfigHistory/ConfigHistory.vue')['default']
ConfigHistoryDiffViewer: typeof import('./src/components/ConfigHistory/DiffViewer.vue')['default']
DevDebugPanelDevDebugPanel: typeof import('./src/components/DevDebugPanel/DevDebugPanel.vue')['default']
FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
GeoLiteDownloadGeoLiteDownload: typeof import('./src/components/GeoLiteDownload/GeoLiteDownload.vue')['default']
ICPICP: typeof import('./src/components/ICP/ICP.vue')['default']
InspectConfigInspectConfig: typeof import('./src/components/InspectConfig/InspectConfig.vue')['default']
LLMChatMessage: typeof import('./src/components/LLM/ChatMessage.vue')['default']
LLMChatMessageInput: typeof import('./src/components/LLM/ChatMessageInput.vue')['default']
LLMChatMessageList: typeof import('./src/components/LLM/ChatMessageList.vue')['default']
LLMLLM: typeof import('./src/components/LLM/LLM.vue')['default']
LLMLLMSessionTabs: typeof import('./src/components/LLM/LLMSessionTabs.vue')['default']
LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
NamespaceRenderNamespaceRender: typeof import('./src/components/NamespaceRender/NamespaceRender.vue')['default']
NamespaceTabsNamespaceTabs: typeof import('./src/components/NamespaceTabs/NamespaceTabs.vue')['default']
NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
NgxConfigEditorDirectiveDirectiveAdd: typeof import('./src/components/NgxConfigEditor/directive/DirectiveAdd.vue')['default']
NgxConfigEditorDirectiveDirectiveDocuments: typeof import('./src/components/NgxConfigEditor/directive/DirectiveDocuments.vue')['default']
NgxConfigEditorDirectiveDirectiveEditor: typeof import('./src/components/NgxConfigEditor/directive/DirectiveEditor.vue')['default']
NgxConfigEditorDirectiveDirectiveEditorItem: typeof import('./src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue')['default']
NgxConfigEditorLocationEditor: typeof import('./src/components/NgxConfigEditor/LocationEditor.vue')['default']
NgxConfigEditorLogEntry: typeof import('./src/components/NgxConfigEditor/LogEntry.vue')['default']
NgxConfigEditorNginxStatusAlert: typeof import('./src/components/NgxConfigEditor/NginxStatusAlert.vue')['default']
NgxConfigEditorNgxConfigEditor: typeof import('./src/components/NgxConfigEditor/NgxConfigEditor.vue')['default']
NgxConfigEditorNgxServer: typeof import('./src/components/NgxConfigEditor/NgxServer.vue')['default']
NgxConfigEditorNgxUpstream: typeof import('./src/components/NgxConfigEditor/NgxUpstream.vue')['default']
NodeCardNodeCard: typeof import('./src/components/NodeCard/NodeCard.vue')['default']
NodeIndicatorNodeIndicator: typeof import('./src/components/NodeIndicator/NodeIndicator.vue')['default']
NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']
NotificationNotification: typeof import('./src/components/Notification/Notification.vue')['default']
OTPInputOTPInput: typeof import('./src/components/OTPInput/OTPInput.vue')['default']
PageHeaderPageHeader: typeof import('./src/components/PageHeader/PageHeader.vue')['default']
PortScannerPortScannerCompact: typeof import('./src/components/PortScanner/PortScannerCompact.vue')['default']
ProcessingStatusProcessingStatus: typeof import('./src/components/ProcessingStatus/ProcessingStatus.vue')['default']
ProxyTargetsProxyTargets: typeof import('./src/components/ProxyTargets/ProxyTargets.vue')['default']
ReactiveFromNowReactiveFromNow: typeof import('./src/components/ReactiveFromNow/ReactiveFromNow.vue')['default']
RecoveryCodeMigrationWarningRecoveryCodeMigrationWarning: typeof import('./src/components/RecoveryCodeMigrationWarning/RecoveryCodeMigrationWarning.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SelfCheckAsyncErrorDisplay: typeof import('./src/components/SelfCheck/AsyncErrorDisplay.vue')['default']
SelfCheckSelfCheck: typeof import('./src/components/SelfCheck/SelfCheck.vue')['default']
SelfCheckSelfCheckHeaderBanner: typeof import('./src/components/SelfCheck/SelfCheckHeaderBanner.vue')['default']
SensitiveStringSensitiveInput: typeof import('./src/components/SensitiveString/SensitiveInput.vue')['default']
SensitiveStringSensitiveString: typeof import('./src/components/SensitiveString/SensitiveString.vue')['default']
SetLanguageSetLanguage: typeof import('./src/components/SetLanguage/SetLanguage.vue')['default']
StringListInputStringListInput: typeof import('./src/components/StringListInput/StringListInput.vue')['default']
SwitchAppearanceIconsVPIconMoon: typeof import('./src/components/SwitchAppearance/icons/VPIconMoon.vue')['default']
SwitchAppearanceIconsVPIconSun: typeof import('./src/components/SwitchAppearance/icons/VPIconSun.vue')['default']
SwitchAppearanceSwitchAppearance: typeof import('./src/components/SwitchAppearance/SwitchAppearance.vue')['default']
SyncNodesPreviewSyncNodesPreview: typeof import('./src/components/SyncNodesPreview/SyncNodesPreview.vue')['default']
SystemRestoreSystemRestoreContent: typeof import('./src/components/SystemRestore/SystemRestoreContent.vue')['default']
TabFilterTabFilter: typeof import('./src/components/TabFilter/TabFilter.vue')['default']
TwoFAAuthorization: typeof import('./src/components/TwoFA/Authorization.vue')['default']
UpstreamCardsUpstreamCards: typeof import('./src/components/UpstreamCards/UpstreamCards.vue')['default']
UpstreamDetailModalUpstreamDetailModal: typeof import('./src/components/UpstreamDetailModal/UpstreamDetailModal.vue')['default']
VPSwitchVPSwitch: typeof import('./src/components/VPSwitch/VPSwitch.vue')['default']
}
}
// For TSX support
declare global {
const AAlert: typeof import('ant-design-vue/es')['Alert']
const AApp: typeof import('ant-design-vue/es')['App']
const AAutoComplete: typeof import('ant-design-vue/es')['AutoComplete']
const AAvatar: typeof import('ant-design-vue/es')['Avatar']
const ABadge: typeof import('ant-design-vue/es')['Badge']
const ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
const ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
const AButton: typeof import('ant-design-vue/es')['Button']
const ACard: typeof import('ant-design-vue/es')['Card']
const ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
const ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
const ACol: typeof import('ant-design-vue/es')['Col']
const ACollapse: typeof import('ant-design-vue/es')['Collapse']
const ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
const AComment: typeof import('ant-design-vue/es')['Comment']
const AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
const ADivider: typeof import('ant-design-vue/es')['Divider']
const ADrawer: typeof import('ant-design-vue/es')['Drawer']
const ADropdown: typeof import('ant-design-vue/es')['Dropdown']
const AEmpty: typeof import('ant-design-vue/es')['Empty']
const AForm: typeof import('ant-design-vue/es')['Form']
const AFormItem: typeof import('ant-design-vue/es')['FormItem']
const AInput: typeof import('ant-design-vue/es')['Input']
const AInputGroup: typeof import('ant-design-vue/es')['InputGroup']
const AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
const AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
const ALayout: typeof import('ant-design-vue/es')['Layout']
const ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
const ALayoutFooter: typeof import('ant-design-vue/es')['LayoutFooter']
const ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
const ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
const AList: typeof import('ant-design-vue/es')['List']
const AListItem: typeof import('ant-design-vue/es')['ListItem']
const AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
const AMenu: typeof import('ant-design-vue/es')['Menu']
const AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
const AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
const AModal: typeof import('ant-design-vue/es')['Modal']
const APagination: typeof import('ant-design-vue/es')['Pagination']
const APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
const APopover: typeof import('ant-design-vue/es')['Popover']
const AppProviderAppProvider: typeof import('./src/components/AppProvider/AppProvider.vue')['default']
const AProgress: typeof import('ant-design-vue/es')['Progress']
const AQrcode: typeof import('ant-design-vue/es')['QRCode']
const ARadio: typeof import('ant-design-vue/es')['Radio']
const ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
const ARangePicker: typeof import('ant-design-vue/es/date-picker/dayjs')['RangePicker']
const AResult: typeof import('ant-design-vue/es')['Result']
const ARow: typeof import('ant-design-vue/es')['Row']
const ASegmented: typeof import('ant-design-vue/es')['Segmented']
const ASelect: typeof import('ant-design-vue/es')['Select']
const ASelectOptGroup: typeof import('ant-design-vue/es')['SelectOptGroup']
const ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
const ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
const ASpace: typeof import('ant-design-vue/es')['Space']
const ASpin: typeof import('ant-design-vue/es')['Spin']
const AStatistic: typeof import('ant-design-vue/es')['Statistic']
const AStep: typeof import('ant-design-vue/es')['Step']
const ASteps: typeof import('ant-design-vue/es')['Steps']
const ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
const ASwitch: typeof import('ant-design-vue/es')['Switch']
const ATable: typeof import('ant-design-vue/es')['Table']
const ATabPane: typeof import('ant-design-vue/es')['TabPane']
const ATabs: typeof import('ant-design-vue/es')['Tabs']
const ATag: typeof import('ant-design-vue/es')['Tag']
const ATextarea: typeof import('ant-design-vue/es')['Textarea']
const ATooltip: typeof import('ant-design-vue/es')['Tooltip']
const ATypographyParagraph: typeof import('ant-design-vue/es')['TypographyParagraph']
const ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
const ATypographyTitle: typeof import('ant-design-vue/es')['TypographyTitle']
const AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
const AutoCertFormAutoCertForm: typeof import('./src/components/AutoCertForm/AutoCertForm.vue')['default']
const AutoCertFormDNSChallenge: typeof import('./src/components/AutoCertForm/DNSChallenge.vue')['default']
const BaseEditorBaseEditor: typeof import('./src/components/BaseEditor/BaseEditor.vue')['default']
const BreadcrumbBreadcrumb: typeof import('./src/components/Breadcrumb/Breadcrumb.vue')['default']
const CertInfoCertInfo: typeof import('./src/components/CertInfo/CertInfo.vue')['default']
const ChartAreaChart: typeof import('./src/components/Chart/AreaChart.vue')['default']
const ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default']
const ChartUsageProgressLine: typeof import('./src/components/Chart/UsageProgressLine.vue')['default']
const CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
const ConfigHistoryConfigHistory: typeof import('./src/components/ConfigHistory/ConfigHistory.vue')['default']
const ConfigHistoryDiffViewer: typeof import('./src/components/ConfigHistory/DiffViewer.vue')['default']
const DevDebugPanelDevDebugPanel: typeof import('./src/components/DevDebugPanel/DevDebugPanel.vue')['default']
const FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
const GeoLiteDownloadGeoLiteDownload: typeof import('./src/components/GeoLiteDownload/GeoLiteDownload.vue')['default']
const ICPICP: typeof import('./src/components/ICP/ICP.vue')['default']
const InspectConfigInspectConfig: typeof import('./src/components/InspectConfig/InspectConfig.vue')['default']
const LLMChatMessage: typeof import('./src/components/LLM/ChatMessage.vue')['default']
const LLMChatMessageInput: typeof import('./src/components/LLM/ChatMessageInput.vue')['default']
const LLMChatMessageList: typeof import('./src/components/LLM/ChatMessageList.vue')['default']
const LLMLLM: typeof import('./src/components/LLM/LLM.vue')['default']
const LLMLLMSessionTabs: typeof import('./src/components/LLM/LLMSessionTabs.vue')['default']
const LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
const NamespaceRenderNamespaceRender: typeof import('./src/components/NamespaceRender/NamespaceRender.vue')['default']
const NamespaceTabsNamespaceTabs: typeof import('./src/components/NamespaceTabs/NamespaceTabs.vue')['default']
const NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
const NgxConfigEditorDirectiveDirectiveAdd: typeof import('./src/components/NgxConfigEditor/directive/DirectiveAdd.vue')['default']
const NgxConfigEditorDirectiveDirectiveDocuments: typeof import('./src/components/NgxConfigEditor/directive/DirectiveDocuments.vue')['default']
const NgxConfigEditorDirectiveDirectiveEditor: typeof import('./src/components/NgxConfigEditor/directive/DirectiveEditor.vue')['default']
const NgxConfigEditorDirectiveDirectiveEditorItem: typeof import('./src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue')['default']
const NgxConfigEditorLocationEditor: typeof import('./src/components/NgxConfigEditor/LocationEditor.vue')['default']
const NgxConfigEditorLogEntry: typeof import('./src/components/NgxConfigEditor/LogEntry.vue')['default']
const NgxConfigEditorNginxStatusAlert: typeof import('./src/components/NgxConfigEditor/NginxStatusAlert.vue')['default']
const NgxConfigEditorNgxConfigEditor: typeof import('./src/components/NgxConfigEditor/NgxConfigEditor.vue')['default']
const NgxConfigEditorNgxServer: typeof import('./src/components/NgxConfigEditor/NgxServer.vue')['default']
const NgxConfigEditorNgxUpstream: typeof import('./src/components/NgxConfigEditor/NgxUpstream.vue')['default']
const NodeCardNodeCard: typeof import('./src/components/NodeCard/NodeCard.vue')['default']
const NodeIndicatorNodeIndicator: typeof import('./src/components/NodeIndicator/NodeIndicator.vue')['default']
const NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']
const NotificationNotification: typeof import('./src/components/Notification/Notification.vue')['default']
const OTPInputOTPInput: typeof import('./src/components/OTPInput/OTPInput.vue')['default']
const PageHeaderPageHeader: typeof import('./src/components/PageHeader/PageHeader.vue')['default']
const PortScannerPortScannerCompact: typeof import('./src/components/PortScanner/PortScannerCompact.vue')['default']
const ProcessingStatusProcessingStatus: typeof import('./src/components/ProcessingStatus/ProcessingStatus.vue')['default']
const ProxyTargetsProxyTargets: typeof import('./src/components/ProxyTargets/ProxyTargets.vue')['default']
const ReactiveFromNowReactiveFromNow: typeof import('./src/components/ReactiveFromNow/ReactiveFromNow.vue')['default']
const RecoveryCodeMigrationWarningRecoveryCodeMigrationWarning: typeof import('./src/components/RecoveryCodeMigrationWarning/RecoveryCodeMigrationWarning.vue')['default']
const RouterLink: typeof import('vue-router')['RouterLink']
const RouterView: typeof import('vue-router')['RouterView']
const SelfCheckAsyncErrorDisplay: typeof import('./src/components/SelfCheck/AsyncErrorDisplay.vue')['default']
const SelfCheckSelfCheck: typeof import('./src/components/SelfCheck/SelfCheck.vue')['default']
const SelfCheckSelfCheckHeaderBanner: typeof import('./src/components/SelfCheck/SelfCheckHeaderBanner.vue')['default']
const SensitiveStringSensitiveInput: typeof import('./src/components/SensitiveString/SensitiveInput.vue')['default']
const SensitiveStringSensitiveString: typeof import('./src/components/SensitiveString/SensitiveString.vue')['default']
const SetLanguageSetLanguage: typeof import('./src/components/SetLanguage/SetLanguage.vue')['default']
const StringListInputStringListInput: typeof import('./src/components/StringListInput/StringListInput.vue')['default']
const SwitchAppearanceIconsVPIconMoon: typeof import('./src/components/SwitchAppearance/icons/VPIconMoon.vue')['default']
const SwitchAppearanceIconsVPIconSun: typeof import('./src/components/SwitchAppearance/icons/VPIconSun.vue')['default']
const SwitchAppearanceSwitchAppearance: typeof import('./src/components/SwitchAppearance/SwitchAppearance.vue')['default']
const SyncNodesPreviewSyncNodesPreview: typeof import('./src/components/SyncNodesPreview/SyncNodesPreview.vue')['default']
const SystemRestoreSystemRestoreContent: typeof import('./src/components/SystemRestore/SystemRestoreContent.vue')['default']
const TabFilterTabFilter: typeof import('./src/components/TabFilter/TabFilter.vue')['default']
const TwoFAAuthorization: typeof import('./src/components/TwoFA/Authorization.vue')['default']
const UpstreamCardsUpstreamCards: typeof import('./src/components/UpstreamCards/UpstreamCards.vue')['default']
const UpstreamDetailModalUpstreamDetailModal: typeof import('./src/components/UpstreamDetailModal/UpstreamDetailModal.vue')['default']
const VPSwitchVPSwitch: typeof import('./src/components/VPSwitch/VPSwitch.vue')['default']
}