@termix-ssh/plugin-sdk 1.0.2 → 1.0.5
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/CHANGELOG.md +31 -0
- package/LICENSE +202 -0
- package/README.md +4 -2
- package/cli/commands/build.mjs +44 -19
- package/cli/commands/dev.mjs +1 -1
- package/cli/commands/migrations.mjs +2 -2
- package/cli/commands/openapi.mjs +39 -0
- package/cli/commands/validate.mjs +72 -0
- package/cli/index.mjs +3 -0
- package/cli/lib/css-classes.mjs +37 -0
- package/dist/changelog.d.ts +3 -1
- package/dist/changelog.js +12 -2
- package/dist/db.d.ts +1 -1
- package/dist/db.js +1 -1
- package/dist/ddl.js +4 -1
- package/dist/docs.d.ts +28 -0
- package/dist/docs.js +39 -0
- package/dist/frontend.d.ts +17 -0
- package/dist/frontend.js +8 -0
- package/dist/host/{chunk-XKMRKQFN.js → chunk-KOOUKYW3.js} +1 -1
- package/dist/host/{chunk-LKYAVM4T.js → chunk-OEOKIKXC.js} +18 -9
- package/dist/host/{chunk-SS43S6VI.js → chunk-VETPF5WI.js} +478 -431
- package/dist/host/core-classes.json +1 -0
- package/dist/host/{linked-server-DW5P3NLZ.js → linked-server-RWBK427T.js} +1 -1
- package/dist/host/{rbac-api-JKISXZEP.js → rbac-api-UJGGTQVA.js} +1 -1
- package/dist/host/testing-host.js +3 -3
- package/dist/host/types/src/types/credential-sidebar-preferences.d.ts +1 -1
- package/dist/host/types/src/ui/api/plugins-api.d.ts +6 -0
- package/dist/host/types/src/ui/components/docs-link.d.ts +25 -0
- package/dist/host/types/src/ui/components/panel-layout.d.ts +3 -1
- package/dist/host/types/src/ui/lib/docs.d.ts +10 -0
- package/dist/host/types/src/ui/lib/error-message.d.ts +1 -1
- package/dist/host/types/src/ui/main-axios.d.ts +1 -2
- package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +1 -0
- package/dist/host/ui.js +18 -8
- package/dist/host/{use-permissions-5CZEA3P4.js → use-permissions-P3DC7ZDR.js} +1 -1
- package/dist/host-commands.js +1 -1
- package/dist/manifest.d.ts +7 -1
- package/dist/manifest.js +48 -1
- package/dist/openapi.d.ts +43 -0
- package/dist/openapi.js +60 -0
- package/dist/testing/setup.js +1 -0
- package/package.json +22 -1
- package/schema/manifest.schema.json +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["!max-h-[60px]","!mt-0","!opacity-100","!running","**:data-[slot=kbd]:isolate","**:data-[slot=kbd]:relative","**:data-[slot=kbd]:rounded-none","**:data-[slot=kbd]:z-50","*:[a]:hover:text-foreground","*:[a]:underline","*:[a]:underline-offset-3","*:[img:first-child]:rounded-none","*:[img:last-child]:rounded-none","*:[span]:last:flex","*:[span]:last:gap-2","*:[span]:last:items-center","*:data-[slot=alert-description]:text-destructive/90","*:data-[slot=select-value]:flex","*:data-[slot=select-value]:gap-2","*:data-[slot=select-value]:items-center","*:data-[slot=select-value]:line-clamp-1","-bottom-1.5","-left-1.5","-left-px","-mt-0.5","-mt-1","-mt-[3.5px]","-mx-1","-mx-3","-my-1","-right-1.5","-right-2","-right-2.5","-right-px","-top-1.5","-top-[3px]","-translate-x-1/2","-translate-x-px","-translate-y-1/2","2xl:flex","2xl:grid-cols-4","3","@container","@container/card-header","@md:grid-cols-2","[&::-webkit-inner-spin-button]:appearance-none","[&::-webkit-outer-spin-button]:appearance-none","[&::-webkit-scrollbar]:hidden","[&>*:last-child]:border-b-0","[&>*]:h-full","[&>*]:shrink-0","[&>button]:hidden","[&>span:last-child]:truncate","[&>svg]:pointer-events-none","[&>svg]:shrink-0","[&>svg]:size-3","[&>svg]:size-4","[&>svg]:text-current","[&>svg]:text-sidebar-accent-foreground","[&>svg]:translate-y-0.5","[&_[cmdk-group-heading]]:font-medium","[&_[cmdk-group-heading]]:px-2","[&_[cmdk-group-heading]]:py-1.5","[&_[cmdk-group-heading]]:text-muted-foreground","[&_[cmdk-group-heading]]:text-xs","[&_[cmdk-list-sizer]]:flex","[&_[cmdk-list-sizer]]:flex-col","[&_p]:leading-relaxed","[&_svg:not([class*='size-'])]:size-3","[&_svg:not([class*='size-'])]:size-3.5","[&_svg:not([class*='size-'])]:size-4","[&_svg:not([class*='text-'])]:text-muted-foreground","[&_svg]:pointer-events-none","[&_svg]:shrink-0","[&_svg]:size-2.5","[&_svg]:size-3","[&_svg]:size-3.5","[&_svg]:size-4","[.border-b]:pb-4","[.gap-4>&]:border-0","[.gap-4>&]:py-0","[@media(hover:none)]:flex","[[data-side=left][data-collapsible=offcanvas]_&]:-right-2","[[data-side=left][data-state=collapsed]_&]:cursor-e-resize","[[data-side=right][data-collapsible=offcanvas]_&]:-left-2","[[data-side=right][data-state=collapsed]_&]:cursor-w-resize","[a&]:hover:bg-accent","[a&]:hover:bg-destructive/90","[a&]:hover:bg-primary/90","[a&]:hover:bg-secondary/90","[a&]:hover:text-accent-foreground","[a]:hover:bg-primary/80","[animation-duration:900ms]","[appearance:textfield]","[backend:stderr]","[clip-path:inset(0px_-4px_-4px_-4px)]","[contain:content]","[op:http_server_port_conflict]","[scrollbar-width:none]","absolute","accent-[var(--accent-brand)]","active:bg-muted","active:bg-muted/60","active:bg-sidebar-accent","active:cursor-grabbing","active:not-aria-[haspopup]:translate-y-px","active:text-sidebar-accent-foreground","after:-inset-2","after:absolute","after:inset-y-0","after:start-1/2","after:w-[2px]","animate-pulse","animate-spin","appearance-none","aria-disabled:opacity-50","aria-disabled:pointer-events-none","aria-expanded:bg-muted","aria-expanded:bg-secondary","aria-expanded:opacity-100","aria-expanded:text-foreground","aria-expanded:text-secondary-foreground","aria-invalid:border-destructive","aria-invalid:ring-1","aria-invalid:ring-destructive/20","aspect-square","aspect-video","auto-cols-fr","auto-rows-fr","auto-rows-min","before:-top-0.5","before:-top-px","before:absolute","before:bg-accent-brand","before:h-0.5","before:inset-x-0","before:inset-x-1","before:z-20","bg-accent-brand","bg-accent-brand/10","bg-accent-brand/15","bg-accent-brand/20","bg-accent-brand/25","bg-accent-brand/40","bg-accent-brand/5","bg-accent-brand/60","bg-accent-brand/70","bg-accent-brand/[0.07]","bg-accent/30","bg-accent/60","bg-background","bg-background/50","bg-background/60","bg-background/70","bg-background/85","bg-background/90","bg-black","bg-black/10","bg-blue-500/20","bg-border","bg-border/60","bg-canvas","bg-card","bg-clip-padding","bg-destructive","bg-destructive/10","bg-destructive/15","bg-destructive/5","bg-destructive/70","bg-emerald-500","bg-emerald-500/10","bg-foreground","bg-green-500","bg-green-500/10","bg-green-500/70","bg-input","bg-muted","bg-muted-foreground","bg-muted-foreground/15","bg-muted-foreground/20","bg-muted-foreground/25","bg-muted-foreground/30","bg-muted-foreground/40","bg-muted-foreground/50","bg-muted/10","bg-muted/15","bg-muted/20","bg-muted/30","bg-muted/40","bg-muted/50","bg-muted/60","bg-muted/70","bg-muted/[0.08]","bg-overlay","bg-popover","bg-primary","bg-red-400","bg-red-500","bg-red-500/10","bg-red-500/40","bg-secondary","bg-sidebar","bg-sidebar-border","bg-surface","bg-surface-dim/40","bg-surface-dim/60","bg-surface/40","bg-transparent","bg-warning","bg-warning/10","bg-warning/20","bg-warning/40","bg-warning/5","bg-warning/70","block","blur","border","border-0","border-2","border-accent-brand","border-accent-brand/20","border-accent-brand/30","border-accent-brand/40","border-accent-brand/50","border-accent-brand/60","border-accent-brand/70","border-b","border-b-2","border-b-accent-brand","border-border","border-border/30","border-border/40","border-border/50","border-border/60","border-current","border-dashed","border-destructive","border-destructive/20","border-destructive/30","border-destructive/40","border-destructive/50","border-emerald-500/40","border-foreground","border-foreground/10","border-green-500/30","border-green-500/40","border-input","border-l","border-l-2","border-l-transparent","border-muted-foreground/30","border-primary","border-r","border-red-500/40","border-sidebar-border","border-t","border-t-0","border-t-border/40","border-t-muted-foreground/70","border-t-transparent","border-transparent","border-warning/30","border-warning/40","border-x","border-y","bottom-0","bottom-4","break-all","break-words","capitalize","catppuccin","col-span-2","col-start-2","collapse","columns-2","columns-3","com","container","contents","cursor-col-resize","cursor-default","cursor-grab","cursor-not-allowed","cursor-ns-resize","cursor-pointer","cursor-row-resize","dark","dark:aria-invalid:border-destructive/50","dark:aria-invalid:ring-destructive/40","dark:bg-destructive/20","dark:bg-destructive/60","dark:bg-input/30","dark:bg-transparent","dark:border-accent-brand/40","dark:border-input","dark:data-[state=active]:bg-input/30","dark:data-[state=active]:border-input","dark:data-[state=active]:text-foreground","dark:data-[state=checked]:bg-primary","dark:data-[state=checked]:bg-primary-foreground","dark:data-[state=unchecked]:bg-foreground","dark:data-[state=unchecked]:bg-input/80","dark:data-[variant=destructive]:focus:bg-destructive/20","dark:disabled:bg-input/80","dark:focus-visible:ring-destructive/40","dark:hover:bg-accent-brand/10","dark:hover:bg-destructive/10","dark:hover:bg-destructive/30","dark:hover:bg-input/50","dark:hover:bg-muted/50","dark:text-muted-foreground","data-[disabled=true]:opacity-50","data-[disabled=true]:pointer-events-none","data-[disabled]:opacity-50","data-[disabled]:pointer-events-none","data-[orientation=horizontal]:h-1.5","data-[orientation=horizontal]:h-full","data-[orientation=horizontal]:h-px","data-[orientation=horizontal]:w-full","data-[orientation=vertical]:flex-col","data-[orientation=vertical]:h-full","data-[orientation=vertical]:min-h-44","data-[orientation=vertical]:self-center","data-[orientation=vertical]:self-stretch","data-[orientation=vertical]:w-1.5","data-[orientation=vertical]:w-auto","data-[orientation=vertical]:w-full","data-[orientation=vertical]:w-px","data-[placeholder]:text-muted-foreground","data-[selected=true]:bg-muted","data-[selected=true]:text-accent-foreground","data-[side=bottom]:border-t","data-[side=bottom]:bottom-0","data-[side=bottom]:data-closed:slide-out-to-bottom-10","data-[side=bottom]:data-open:slide-in-from-bottom-10","data-[side=bottom]:h-auto","data-[side=bottom]:inset-x-0","data-[side=bottom]:slide-in-from-top-2","data-[side=bottom]:translate-y-1","data-[side=left]:-translate-x-1","data-[side=left]:border-r","data-[side=left]:data-closed:slide-out-to-left-10","data-[side=left]:data-open:slide-in-from-left-10","data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]","data-[side=left]:h-full","data-[side=left]:inset-y-0","data-[side=left]:left-0","data-[side=left]:slide-in-from-right-2","data-[side=left]:sm:max-w-sm","data-[side=left]:w-3/4","data-[side=right]:border-l","data-[side=right]:data-closed:slide-out-to-right-10","data-[side=right]:data-open:slide-in-from-right-10","data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]","data-[side=right]:h-full","data-[side=right]:inset-y-0","data-[side=right]:right-0","data-[side=right]:slide-in-from-left-2","data-[side=right]:sm:max-w-sm","data-[side=right]:translate-x-1","data-[side=right]:w-3/4","data-[side=top]:-translate-y-1","data-[side=top]:border-b","data-[side=top]:data-closed:slide-out-to-top-10","data-[side=top]:data-open:slide-in-from-top-10","data-[side=top]:h-auto","data-[side=top]:inset-x-0","data-[side=top]:slide-in-from-bottom-2","data-[side=top]:top-0","data-[size=default]:h-9","data-[size=md]:text-xs","data-[size=sm]:gap-2","data-[size=sm]:h-8","data-[size=sm]:has-data-[slot=card-footer]:pb-0","data-[size=sm]:py-3","data-[size=sm]:text-xs","data-[state=active]:animate-in","data-[state=active]:bg-background","data-[state=active]:fade-in-0","data-[state=active]:shadow-sm","data-[state=checked]:bg-primary","data-[state=checked]:border-primary","data-[state=checked]:text-primary-foreground","data-[state=checked]:translate-x-[calc(100%-2px)]","data-[state=closed]:animate-out","data-[state=closed]:fade-out-0","data-[state=closed]:overflow-hidden","data-[state=closed]:zoom-out-95","data-[state=delayed-open]:animate-in","data-[state=delayed-open]:fade-in-0","data-[state=delayed-open]:zoom-in-95","data-[state=inactive]:animate-out","data-[state=inactive]:fade-out-0","data-[state=open]:animate-in","data-[state=open]:fade-in-0","data-[state=open]:zoom-in-95","data-[state=unchecked]:bg-input","data-[state=unchecked]:translate-x-0","data-[variant=destructive]:*:[svg]:text-destructive","data-[variant=destructive]:focus:bg-destructive/10","data-[variant=destructive]:focus:text-destructive","data-[variant=destructive]:text-destructive","data-active:bg-sidebar-accent","data-active:font-medium","data-active:text-sidebar-accent-foreground","data-closed:animate-out","data-closed:fade-out-0","data-closed:zoom-out-95","data-disabled:opacity-50","data-disabled:pointer-events-none","data-inset:pl-7","data-open:animate-in","data-open:bg-accent","data-open:fade-in-0","data-open:hover:bg-sidebar-accent","data-open:hover:text-sidebar-accent-foreground","data-open:text-accent-foreground","data-open:zoom-in-95","delay-75","disabled:bg-input/50","disabled:cursor-not-allowed","disabled:opacity-30","disabled:opacity-40","disabled:opacity-50","disabled:opacity-60","disabled:pointer-events-none","divide-border","divide-x","divide-y","dracula","drop-shadow","duration-100","duration-150","duration-200","duration-500","duration-[450ms]","ease-in-out","ease-linear","ease-out","enabled:hover:text-accent-brand","fade-in","file:bg-transparent","file:border-0","file:font-medium","file:h-6","file:inline-flex","file:text-foreground","file:text-xs","fill-foreground","filter","fixed","flex","flex-1","flex-col","flex-col-reverse","flex-row","flex-wrap","focus-visible:border-destructive/40","focus-visible:border-ring","focus-visible:outline-1","focus-visible:outline-hidden","focus-visible:outline-none","focus-visible:outline-ring","focus-visible:relative","focus-visible:ring-0","focus-visible:ring-1","focus-visible:ring-2","focus-visible:ring-4","focus-visible:ring-[#f59145]/40","focus-visible:ring-[3px]","focus-visible:ring-destructive/20","focus-visible:ring-inset","focus-visible:ring-ring","focus-visible:ring-ring/50","focus-visible:z-10","focus-within:border-ring","focus-within:opacity-100","focus-within:ring-1","focus-within:ring-ring","focus-within:ring-ring/50","focus:**:text-accent-foreground","focus:bg-accent","focus:ring-1","focus:ring-ring","focus:text-accent-brand","focus:text-accent-foreground","focus:text-destructive","font-bold","font-heading","font-medium","font-mono","font-normal","font-semibold","fs-lg","fs-md","fs-sm","fs-xl","fs-xs","gap-0","gap-0.5","gap-1","gap-1.5","gap-2","gap-2.5","gap-3","gap-3.5","gap-4","gap-5","gap-6","gap-[1.75px]","gap-[10.5px]","gap-[2px]","gap-[3.5px]","gap-[3px]","gap-px","gap-x-2","gap-x-3","gap-x-4","gap-x-6","gap-y-0","gap-y-0.5","gap-y-1","gap-y-1.5","gap-y-2","gap-y-3","grid","grid-cols-1","grid-cols-2","grid-cols-3","grid-cols-4","grid-cols-6","grid-cols-8","grid-cols-[0_1fr]","grid-cols-[1fr_5rem]","grid-flow-col","group","group-[.toast]:!border-accent-brand/30","group-[.toast]:!border-destructive/30","group-[.toast]:!text-accent-brand","group-[.toast]:!text-destructive","group-[.toast]:bg-accent-brand","group-[.toast]:bg-muted","group-[.toast]:font-semibold","group-[.toast]:text-muted-foreground","group-[.toast]:text-white","group-[.toaster]:bg-card","group-[.toaster]:border-border","group-[.toaster]:font-mono","group-[.toaster]:rounded-none!","group-[.toaster]:shadow-lg","group-[.toaster]:text-card-foreground","group-data-[collapsible=icon]:-mt-8","group-data-[collapsible=icon]:hidden","group-data-[collapsible=icon]:opacity-0","group-data-[collapsible=icon]:overflow-hidden","group-data-[collapsible=icon]:p-0!","group-data-[collapsible=icon]:p-2!","group-data-[collapsible=icon]:size-8!","group-data-[collapsible=icon]:w-(--sidebar-width-icon)","group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]","group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]","group-data-[collapsible=offcanvas]:after:left-full","group-data-[collapsible=offcanvas]:translate-x-0","group-data-[collapsible=offcanvas]:w-0","group-data-[disabled=true]:opacity-50","group-data-[disabled=true]:pointer-events-none","group-data-[selected=true]:opacity-100","group-data-[side=left]:-right-4","group-data-[side=left]:border-r","group-data-[side=right]:border-l","group-data-[side=right]:left-0","group-data-[side=right]:rotate-180","group-data-[size=sm]/card:[.border-b]:pb-3","group-data-[size=sm]/card:p-3","group-data-[size=sm]/card:px-3","group-data-[size=sm]/card:text-sm","group-data-[variant=floating]:ring-1","group-data-[variant=floating]:ring-sidebar-border","group-data-[variant=floating]:rounded-none","group-data-[variant=floating]:shadow-sm","group-focus-within/folder:flex","group-focus-within/menu-item:opacity-100","group-focus-within/row:flex","group-focus/dropdown-menu-item:text-accent-foreground","group-has-data-[sidebar=menu-action]/menu-item:pr-8","group-hover/btn:bg-accent-brand/20","group-hover/btn:border-accent-brand/40","group-hover/folder:flex","group-hover/folder:opacity-100","group-hover/folder:text-muted-foreground/70","group-hover/menu-item:opacity-100","group-hover/open:text-accent-brand","group-hover/resize:bg-accent-brand/60","group-hover/row:flex","group-hover/row:text-muted-foreground/60","group-hover/tab:opacity-100","group-hover:bg-accent-brand/60","group-hover:hidden","group-hover:max-h-[60px]","group-hover:mt-0","group-hover:opacity-100","group-hover:text-muted-foreground/70","group/btn","group/card","group/dropdown-menu-item","group/folder","group/menu-item","group/open","group/resize","group/row","group/tab","grow","gruvbox","h-0","h-0.5","h-1","h-1.5","h-10","h-11","h-12","h-12.5","h-14","h-16","h-2.5","h-20","h-24","h-28","h-3","h-3.5","h-4","h-5","h-6","h-7","h-8","h-9","h-[1.15rem]","h-[136px]","h-[14px]","h-[2px]","h-[3px]","h-[46%]","h-[calc(100%-1px)]","h-[var(--radix-select-trigger-height)]","h-full","h-px","h-screen","h-svh","has-[>img:first-child]:pt-0","has-[>svg]:gap-x-3","has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr]","has-[[data-state=open]]:opacity-100","has-data-[icon=inline-end]:pr-1.5","has-data-[icon=inline-end]:pr-2","has-data-[icon=inline-start]:pl-1.5","has-data-[icon=inline-start]:pl-2","has-data-[slot=card-action]:grid-cols-[1fr_auto]","has-data-[slot=card-description]:grid-rows-[auto_auto]","has-data-[slot=card-footer]:pb-0","has-data-[slot=kbd]:pr-1.5","has-data-[variant=inset]:bg-sidebar","hidden","host-status-stripe","hover:after:bg-sidebar-border","hover:bg-accent","hover:bg-accent-brand","hover:bg-accent-brand/10","hover:bg-accent-brand/15","hover:bg-accent-brand/20","hover:bg-accent-brand/40","hover:bg-accent-brand/5","hover:bg-accent-brand/90","hover:bg-background/80","hover:bg-destructive/10","hover:bg-destructive/20","hover:bg-destructive/90","hover:bg-foreground/[0.03]","hover:bg-muted","hover:bg-muted-foreground/10","hover:bg-muted/20","hover:bg-muted/30","hover:bg-muted/40","hover:bg-muted/50","hover:bg-muted/60","hover:bg-secondary/80","hover:bg-sidebar-accent","hover:bg-surface","hover:border-accent-brand","hover:border-accent-brand/30","hover:border-accent-brand/40","hover:border-accent-brand/60","hover:border-destructive/40","hover:border-foreground/40","hover:border-muted-foreground","hover:border-ring/60","hover:group-data-[collapsible=offcanvas]:bg-sidebar","hover:opacity-100","hover:ring-4","hover:ring-[#f59145]/40","hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]","hover:text-accent-brand","hover:text-accent-brand/70","hover:text-accent-brand/80","hover:text-accent-foreground","hover:text-destructive","hover:text-destructive/80","hover:text-foreground","hover:text-muted-foreground","hover:text-primary","hover:text-sidebar-accent-foreground","hover:underline","in-data-[side=left]:cursor-w-resize","in-data-[side=right]:cursor-e-resize","inline","inline-block","inline-flex","inset-0","inset-x-0","inset-x-3","inset-y-0","invisible","isolate","italic","items-baseline","items-center","items-end","items-start","items-stretch","justify-between","justify-center","justify-end","justify-items-start","justify-self-end","justify-start","last:border-0","last:border-b-0","leading-[1.4]","leading-[1.7]","leading-[14px]","leading-none","leading-relaxed","leading-snug","leading-tight","left-0","left-1/2","left-2","left-2.5","left-[50%]","lg:block","lg:col-span-2","lg:flex","lg:grid-cols-1","lg:grid-cols-2","lg:grid-cols-3","lg:grid-cols-4","lg:grid-cols-5","lg:hidden","lg:inline","line-clamp-2","line-clamp-3","line-clamp-4","line-through","list-disc","list-inside","lowercase","ltr:-translate-x-1/2","lucide","m-2.5","m-auto","max-h-(--radix-dropdown-menu-content-available-height)","max-h-(--radix-popover-content-available-height)","max-h-(--radix-select-content-available-height)","max-h-0","max-h-24","max-h-40","max-h-56","max-h-64","max-h-96","max-h-[130px]","max-h-[300px]","max-h-[60px]","max-h-[60vh]","max-h-[80dvh]","max-w-(--skeleton-width)","max-w-0","max-w-2xl","max-w-32","max-w-3xl","max-w-40","max-w-48","max-w-5xl","max-w-72","max-w-96","max-w-[120px]","max-w-[160px]","max-w-[180px]","max-w-[200px]","max-w-[260px]","max-w-[380px]","max-w-[50%]","max-w-[560px]","max-w-[5rem]","max-w-[60%]","max-w-[calc(100%-2rem)]","max-w-full","max-w-lg","max-w-md","max-w-sm","max-w-xl","max-w-xs","mb-0.5","mb-1","mb-1.5","mb-2","mb-4","md:-mx-4","md:after:hidden","md:block","md:col-span-1","md:flex","md:flex-row","md:grid-cols-1","md:grid-cols-2","md:grid-cols-3","md:grid-cols-4","md:hidden","md:max-h-none","md:opacity-0","md:overflow-visible","md:overflow-y-auto","md:peer-data-[variant=inset]:m-2","md:peer-data-[variant=inset]:ml-0","md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2","md:peer-data-[variant=inset]:rounded-none","md:peer-data-[variant=inset]:shadow-sm","md:px-3.5","md:px-4","md:size-4","md:static","md:text-2xl","md:text-xs","md:w-44","md:w-48","md:w-56","md:w-60","md:w-72","min-[280px]:inline","min-h-0","min-h-11","min-h-16","min-h-24","min-h-48","min-h-8","min-h-9","min-h-[19px]","min-h-[220px]","min-h-[70vh]","min-h-[80px]","min-h-full","min-h-svh","min-w-(--radix-popover-trigger-width)","min-w-0","min-w-16","min-w-3","min-w-32","min-w-4","min-w-40","min-w-44","min-w-5","min-w-52","min-w-[14px]","min-w-[150px]","min-w-[160px]","min-w-[170px]","min-w-[180px]","min-w-[200px]","min-w-[8rem]","min-w-[96px]","min-w-[var(--radix-select-trigger-width)]","min-w-max","ml-0.5","ml-1","ml-1.5","ml-2","ml-3","ml-3.5","ml-4","ml-8","ml-[27px]","ml-auto","motion-context-enter","motion-fade-enter","motion-interactive","motion-meter","motion-panel-enter","motion-transfer-phase","motion-workspace-enter","motion-workspace-layout","mr-1","mr-1.5","mr-2","mt-0.5","mt-1","mt-1.5","mt-2","mt-2.5","mt-3","mt-4","mt-[1.75px]","mt-auto","mt-px","mx-0.5","mx-2","mx-3.5","mx-4","mx-auto","my-0.5","my-1","my-3","my-auto","nord","normal-case","not-data-[variant=destructive]:focus:**:text-accent-foreground","object-contain","one-dark","opacity-0","opacity-100","opacity-40","opacity-50","opacity-60","opacity-70","opacity-80","origin-(--radix-dropdown-menu-content-transform-origin)","origin-(--radix-popover-content-transform-origin)","origin-(--radix-select-content-transform-origin)","origin-(--radix-tooltip-content-transform-origin)","origin-center","outline","outline-hidden","outline-none","overflow-auto","overflow-hidden","overflow-x-auto","overflow-x-hidden","overflow-y-auto","overflow-y-hidden","overline","p-0","p-0.5","p-1","p-1.5","p-10","p-2","p-2.5","p-3","p-4","p-5","p-6","p-8","p-[3px]","p-px","paused","pb-0","pb-1","pb-1.5","pb-2","pb-3","pb-6","peer","peer-data-[size=default]/menu-button:top-1.5","peer-data-[size=lg]/menu-button:top-2.5","peer-data-[size=sm]/menu-button:top-1","peer-data-active/menu-button:text-sidebar-accent-foreground","peer-disabled:cursor-not-allowed","peer-disabled:opacity-50","peer-hover/menu-button:text-sidebar-accent-foreground","peer/menu-button","pl-1","pl-2","pl-2.5","pl-4","pl-5","pl-5.5","pl-6","pl-7","pl-8","pl-[7px]","pl-[8.75px]","pl-px","placeholder:text-muted-foreground","placeholder:text-muted-foreground/50","pointer-coarse:flex","pointer-coarse:opacity-100","pointer-events-none","pr-0.5","pr-1","pr-1.5","pr-12","pr-2","pr-2.5","pr-7","pr-8","pr-9","pr-[5.25px]","pr-[7px]","pt-0.5","pt-1","pt-1.5","pt-2","pt-2.5","pt-3","pt-4","pt-[15vh]","pt-[3.5px]","pt-[3px]","pt-[5.25px]","px-0","px-0.5","px-1","px-1.5","px-2","px-2.5","px-3","px-3.5","px-4","px-5","px-6","px-[3px]","py-0","py-0.5","py-1","py-1.5","py-10","py-12","py-2","py-2.5","py-3","py-4","py-6","py-8","py-[1px]","py-[2px]","py-[5px]","py-[7px]","py-px","relative","resize","resize-none","right-0","right-1","right-1.5","right-2","right-2.5","right-3","ring","ring-0","ring-1","ring-2","ring-accent-brand","ring-accent-brand/50","ring-border","ring-foreground/10","ring-inset","ring-offset-1","ring-offset-background","ring-sidebar-ring","ring-white/60","rotate-180","rotate-45","rotate-90","rounded","rounded-[inherit]","rounded-full","rounded-none","rounded-sm","row-span-2","row-start-1","rtl:-translate-x-1/2","running","safe-bottom","scale-110","scroll-my-1","scrollbar-none","select-none","self-end","self-start","self-stretch","settings-search-hit","shadow","shadow-2xl","shadow-[0_0_0_1px_hsl(var(--sidebar-border))]","shadow-lg","shadow-md","shadow-none","shadow-sm","shadow-xl","shadow-xs","shrink-0","size-1.5","size-10","size-12","size-2","size-2.5","size-3","size-3.5","size-4","size-5","size-6","size-6.5","size-7","size-8","size-9","size-[10.5px]","size-[17.5px]","size-[19px]","size-[22.75px]","size-full","size-px","sm:border-b-0","sm:border-r","sm:col-span-2","sm:flex","sm:flex-row","sm:grid-cols-12","sm:grid-cols-2","sm:grid-cols-3","sm:grid-cols-4","sm:items-center","sm:justify-end","sm:max-w-lg","sm:max-w-sm","sm:mr-auto","sm:py-14","sm:text-left","solarized","space-y-0.5","space-y-1.5","space-y-2","sr-only","static","sticky","stroke-accent-brand","stroke-border","stroke-muted","supports-backdrop-filter:backdrop-blur-xs","tab-1","tab-2","table","tabular-nums","text-2xl","text-[10px]","text-[11px]","text-[12px]","text-[13px]","text-[9px]","text-accent-brand","text-accent-brand/50","text-accent-brand/80","text-accent-foreground","text-background","text-base","text-blue-400","text-blue-500","text-card-foreground","text-center","text-current","text-destructive","text-destructive/80","text-emerald-500","text-foreground","text-foreground-secondary","text-foreground/70","text-foreground/80","text-green-500","text-left","text-lg","text-muted-foreground","text-muted-foreground/0","text-muted-foreground/20","text-muted-foreground/30","text-muted-foreground/35","text-muted-foreground/40","text-muted-foreground/45","text-muted-foreground/50","text-muted-foreground/60","text-muted-foreground/70","text-muted-foreground/80","text-popover-foreground","text-primary","text-primary-foreground","text-red-500","text-right","text-secondary-foreground","text-sidebar-foreground","text-sidebar-foreground/70","text-sm","text-warning","text-white","text-xl","text-xs","text-xs/relaxed","thin-scrollbar","toast","toaster","tokyo-night","top-0","top-1","top-1.5","top-1/2","top-2","top-20","top-3","top-3.5","top-[50%]","touch-none","tracking-[0.35em]","tracking-[0.3em]","tracking-normal","tracking-tight","tracking-wide","tracking-wider","tracking-widest","transfer-progress-fill","transfer-progress-indeterminate","transfer-progress-stalled","transfer-progress-track","transform","transition","transition-[background-color,border-color,box-shadow,opacity]","transition-[color,background-color,border-color,opacity,box-shadow,transform]","transition-[color,box-shadow]","transition-[height,border-color]","transition-[height]","transition-[left,right,width]","transition-[left,top,width,height]","transition-[margin,opacity]","transition-[max-height,opacity,margin]","transition-[opacity,max-width]","transition-[opacity,width]","transition-[padding]","transition-[stroke-dasharray]","transition-[width,height,padding]","transition-[width]","transition-all","transition-colors","transition-none","transition-opacity","transition-shadow","transition-transform","translate-x-0.5","translate-x-4","translate-x-[-50%]","translate-x-px","translate-y-[-1px]","translate-y-[-50%]","translate-y-[calc(-50%_-_2px)]","truncate","underline","underline-offset-2","underline-offset-4","uppercase","visible","w-(--radix-dropdown-menu-trigger-width)","w-(--sidebar-width)","w-0","w-0.5","w-1","w-1.5","w-1/2","w-1/4","w-10","w-11","w-12","w-12.5","w-2","w-2.5","w-2/3","w-20","w-28","w-3","w-3/4","w-4","w-40","w-48","w-5","w-5/6","w-52","w-56","w-6","w-60","w-64","w-72","w-8","w-9","w-[240px]","w-[2px]","w-[3px]","w-[46%]","w-[min(85vw,360px)]","w-[var(--radix-popover-trigger-width)]","w-auto","w-fit","w-full","w-max","w-px","w-screen","whitespace-normal","whitespace-nowrap","whitespace-pre","whitespace-pre-line","whitespace-pre-wrap","xl:block","xl:flex","xl:grid-cols-1","xl:grid-cols-2","xl:grid-cols-3","xl:grid-cols-4","z-0","z-10","z-20","z-30","z-40","z-50","z-500","z-[10000]","z-[100]","z-[200]","z-[60]","z-[9998]","z-[99999]"]
|
|
@@ -40,16 +40,16 @@ import {
|
|
|
40
40
|
setShellCallbacks,
|
|
41
41
|
setShellHosts,
|
|
42
42
|
setShellLayoutProvider
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-VETPF5WI.js";
|
|
44
44
|
import {
|
|
45
45
|
setPermissionsForTesting
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-KOOUKYW3.js";
|
|
47
47
|
import {
|
|
48
48
|
getTabType,
|
|
49
49
|
listTabTypes,
|
|
50
50
|
setFrontendState,
|
|
51
51
|
setPluginSummaries
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-OEOKIKXC.js";
|
|
53
53
|
import "./chunk-YC2MAKSP.js";
|
|
54
54
|
|
|
55
55
|
// src/ui/plugin-host/testing-host.tsx
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Credential sidebar preferences model. Shared by the frontend sidebar and
|
|
3
3
|
* the backend preferences endpoint (no framework imports, mirrors
|
|
4
4
|
* ./host-sidebar-preferences.ts's dependency-free convention). Independent
|
|
5
|
-
* from HostSidebarPreferences by design
|
|
5
|
+
* from HostSidebarPreferences by design, a separate parallel system, not a
|
|
6
6
|
* shared blob, matching how credentialSortKey/credentialFilterState were
|
|
7
7
|
* already independently namespaced from hostSortKey/etc. before this port.
|
|
8
8
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ChoiceAdjustment, PluginChoice } from "../../types/plugin-onboarding";
|
|
2
2
|
import type { ChangelogRelease, ReleaseNotes } from "@termix-ssh/plugin-sdk/changelog";
|
|
3
|
+
import type { PluginEnvVar } from "@termix-ssh/plugin-sdk/docs";
|
|
3
4
|
export type { PluginChoice };
|
|
4
5
|
export interface PluginTabContribution {
|
|
5
6
|
id: string;
|
|
@@ -138,6 +139,10 @@ export interface PluginSummary {
|
|
|
138
139
|
videoId?: string;
|
|
139
140
|
/** What the plugin does, from the manifest. Admins only. */
|
|
140
141
|
features?: string[];
|
|
142
|
+
/** https docs link from the manifest. */
|
|
143
|
+
docs?: string;
|
|
144
|
+
/** Environment variables the plugin reads. Admins only. */
|
|
145
|
+
env?: PluginEnvVar[];
|
|
141
146
|
signedBy?: string | null;
|
|
142
147
|
}
|
|
143
148
|
export declare function getPlugins(): Promise<PluginSummary[]>;
|
|
@@ -165,6 +170,7 @@ export interface RegistryPluginEntry {
|
|
|
165
170
|
icon?: string;
|
|
166
171
|
videoId?: string;
|
|
167
172
|
features?: string[];
|
|
173
|
+
docs?: string;
|
|
168
174
|
versions: RegistryPluginVersion[];
|
|
169
175
|
/** Newest release on the plugin's channel. */
|
|
170
176
|
latestVersion: string | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type DocsPage } from "../lib/docs";
|
|
3
|
+
/** A plugin's docs link from its manifest, or null when it has none. */
|
|
4
|
+
export declare function usePluginDocsUrl(pluginId: string | null | undefined, page?: string, anchor?: string): string | null;
|
|
5
|
+
export interface DocsLinkProps {
|
|
6
|
+
/** A core docs page. */
|
|
7
|
+
core?: DocsPage;
|
|
8
|
+
/**
|
|
9
|
+
* A page of the current plugin's docs, like "setup". Inside a plugin this
|
|
10
|
+
* resolves against its manifest docs link; "" is its main page.
|
|
11
|
+
*/
|
|
12
|
+
page?: string;
|
|
13
|
+
anchor?: string;
|
|
14
|
+
/** A full URL, used as is. */
|
|
15
|
+
href?: string | null;
|
|
16
|
+
/** "text" is a small inline link, "icon" a square header button. */
|
|
17
|
+
variant?: "text" | "icon";
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The one way the app links to docs. Renders nothing when there is nowhere
|
|
23
|
+
* to go, like a community plugin with no docs link.
|
|
24
|
+
*/
|
|
25
|
+
export declare function DocsLink({ core, page, anchor, href, variant, children, className, }: DocsLinkProps): import("react").JSX.Element;
|
|
@@ -10,7 +10,7 @@ export declare const PANEL: {
|
|
|
10
10
|
export type PanelViewMode = "grid" | "list";
|
|
11
11
|
export type PanelDensity = "comfortable" | "compact";
|
|
12
12
|
/** The header, toolbar band and body every tab and panel draws. */
|
|
13
|
-
export declare function PanelShell({ chrome, icon, title, status, leading, actions, toolbar, tabs, footer, scroll, className, children, }: {
|
|
13
|
+
export declare function PanelShell({ chrome, icon, title, status, leading, actions, toolbar, tabs, footer, scroll, docs, className, children, }: {
|
|
14
14
|
/** False inside a sidebar, which draws its own header. */
|
|
15
15
|
chrome?: boolean;
|
|
16
16
|
icon?: React.ReactNode;
|
|
@@ -27,6 +27,8 @@ export declare function PanelShell({ chrome, icon, title, status, leading, actio
|
|
|
27
27
|
footer?: React.ReactNode;
|
|
28
28
|
/** False when the body scrolls itself. */
|
|
29
29
|
scroll?: boolean;
|
|
30
|
+
/** Docs URL for this screen, shown as a book icon in the header. */
|
|
31
|
+
docs?: string | null;
|
|
30
32
|
className?: string;
|
|
31
33
|
children: React.ReactNode;
|
|
32
34
|
}): React.JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import DOCS_PAGES from "./docs-pages.json";
|
|
2
|
+
export declare const DOCS_URL = "https://docs.termix.site";
|
|
3
|
+
/**
|
|
4
|
+
* Every core docs page the app links to. The docs site checks each one
|
|
5
|
+
* exists, so add new links here rather than writing URLs inline.
|
|
6
|
+
*/
|
|
7
|
+
export type DocsPage = keyof typeof DOCS_PAGES;
|
|
8
|
+
/** Full URL of a core docs page. */
|
|
9
|
+
export declare function docsUrl(page?: DocsPage): string;
|
|
10
|
+
export { DOCS_PAGES };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Extract a stable, human-readable message from an unknown thrown value.
|
|
3
3
|
*
|
|
4
|
-
* A thrown value is not guaranteed to be an `Error
|
|
4
|
+
* A thrown value is not guaranteed to be an `Error`, libraries may throw
|
|
5
5
|
* strings or plain objects, which carry no useful `.message`. When that
|
|
6
6
|
* happens the caller gets `fallback` instead, so error paths never surface a
|
|
7
7
|
* raw `[object Object]` in logs or UI.
|
|
@@ -66,7 +66,6 @@ export interface UserInfo {
|
|
|
66
66
|
is_dual_auth?: boolean;
|
|
67
67
|
password_hash?: string;
|
|
68
68
|
data_unlocked?: boolean;
|
|
69
|
-
show_donation_modal?: boolean;
|
|
70
69
|
/** On a desktop linked to a server, the account it is signed in to there. */
|
|
71
70
|
linked?: LinkedAccountInfo | null;
|
|
72
71
|
}
|
|
@@ -83,6 +82,7 @@ interface UserCount {
|
|
|
83
82
|
count: number;
|
|
84
83
|
}
|
|
85
84
|
export { isElectron };
|
|
85
|
+
export declare const TRUST_TOKEN_KEY = "termixTrustToken";
|
|
86
86
|
export declare function setCookie(name: string, value: string, days?: number): void | Promise<void>;
|
|
87
87
|
export declare function getCookie(name: string): string | undefined;
|
|
88
88
|
export declare function markUserAuthenticated(): void;
|
|
@@ -120,7 +120,6 @@ export declare function logoutUser(): Promise<{
|
|
|
120
120
|
message: string;
|
|
121
121
|
}>;
|
|
122
122
|
export declare function getUserInfo(): Promise<UserInfo>;
|
|
123
|
-
export declare function dismissDonationModal(): Promise<void>;
|
|
124
123
|
export declare function getCurrentToken(): Promise<string | null>;
|
|
125
124
|
export declare function unlockUserData(password: string): Promise<{
|
|
126
125
|
success: boolean;
|
|
@@ -87,6 +87,7 @@ export { getAdaptiveResourceBudget, markAdaptiveResourceUsed, runAdaptiveBackgro
|
|
|
87
87
|
export { getDeviceId } from "../lib/device-id";
|
|
88
88
|
export { createQuickConnectHost } from "../sidebar/quick-connect-host";
|
|
89
89
|
export { BackButton, Facts, GroupHeading, PANEL, PanelSearch, PanelShell, Segmented, ViewToggle, type PanelDensity, type PanelViewMode, } from "../components/panel-layout";
|
|
90
|
+
export { DocsLink, type DocsLinkProps } from "../components/docs-link";
|
|
90
91
|
export { AddButton, FormFooter, ListBadge, ListRow, ListRowAction, ListRowFolder, PanelList, type ListRowTone, } from "../components/list-kit";
|
|
91
92
|
export { DataView, type DataColumn, type GridColumns, } from "../components/data-view";
|
|
92
93
|
export { TabStrip, type TabStripItem } from "../components/tab-strip";
|
package/dist/host/ui.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
Copy,
|
|
24
24
|
Corner,
|
|
25
25
|
Description2,
|
|
26
|
+
DocsLink,
|
|
26
27
|
ExternalLink,
|
|
27
28
|
Eye,
|
|
28
29
|
EyeOff,
|
|
@@ -137,8 +138,8 @@ import {
|
|
|
137
138
|
useSurfaceKind,
|
|
138
139
|
useTheme,
|
|
139
140
|
verifySecondFactor
|
|
140
|
-
} from "./chunk-
|
|
141
|
-
import "./chunk-
|
|
141
|
+
} from "./chunk-VETPF5WI.js";
|
|
142
|
+
import "./chunk-KOOUKYW3.js";
|
|
142
143
|
import {
|
|
143
144
|
TabProvider,
|
|
144
145
|
buildOriginWsUrl,
|
|
@@ -177,7 +178,7 @@ import {
|
|
|
177
178
|
useTabs,
|
|
178
179
|
useTabsSafe,
|
|
179
180
|
verifyPasswordResetCode
|
|
180
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-OEOKIKXC.js";
|
|
181
182
|
import "./chunk-YC2MAKSP.js";
|
|
182
183
|
|
|
183
184
|
// src/ui/components/alert.tsx
|
|
@@ -3838,6 +3839,7 @@ function HostPluginSection({
|
|
|
3838
3839
|
{
|
|
3839
3840
|
title: plugin.name,
|
|
3840
3841
|
icon: /* @__PURE__ */ jsx36(PluginIcon, { name: plugin.icon, className: "size-3.5" }),
|
|
3842
|
+
action: /* @__PURE__ */ jsx36(DocsLink, { href: plugin.docs }),
|
|
3841
3843
|
children: [
|
|
3842
3844
|
!running && /* @__PURE__ */ jsx36("div", { className: "my-3 border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning", children: t2("settings.featureUnavailable", { name: plugin.name }) }),
|
|
3843
3845
|
enableKey && /* @__PURE__ */ jsx36(
|
|
@@ -4426,6 +4428,13 @@ function syncPlugins(summaries) {
|
|
|
4426
4428
|
import.meta.hot?.on("termix:plugins-reloaded", () => {
|
|
4427
4429
|
if (started) void syncPlugins();
|
|
4428
4430
|
});
|
|
4431
|
+
function installLocaleResolver() {
|
|
4432
|
+
setPluginLocaleResolver((namespace, _language, file) => {
|
|
4433
|
+
const summary = getPluginRecord(namespace)?.summary;
|
|
4434
|
+
if (!summary) return Promise.resolve(null);
|
|
4435
|
+
return currentDeps().loadLocale(summary, file);
|
|
4436
|
+
});
|
|
4437
|
+
}
|
|
4429
4438
|
async function fetchPreLoginPlugins() {
|
|
4430
4439
|
const response = await fetch(getBackendUrl("/plugins/public-manifest"));
|
|
4431
4440
|
if (!response.ok) return [];
|
|
@@ -4441,11 +4450,7 @@ async function startPreLoginPlugins(options = {}) {
|
|
|
4441
4450
|
return;
|
|
4442
4451
|
}
|
|
4443
4452
|
if (list.length === 0 || started) return;
|
|
4444
|
-
|
|
4445
|
-
const summary = getPluginRecord(namespace)?.summary;
|
|
4446
|
-
if (!summary) return Promise.resolve(null);
|
|
4447
|
-
return currentDeps().loadLocale(summary, file);
|
|
4448
|
-
});
|
|
4453
|
+
installLocaleResolver();
|
|
4449
4454
|
await enqueue(async () => {
|
|
4450
4455
|
if (started) return;
|
|
4451
4456
|
if (options.retryFailed) {
|
|
@@ -5026,6 +5031,10 @@ function Auth({ onLogin }) {
|
|
|
5026
5031
|
toast2.error(t2("auth.secondFactorUnavailable"));
|
|
5027
5032
|
return;
|
|
5028
5033
|
}
|
|
5034
|
+
if (error?.response?.data?.code === "external_login_required") {
|
|
5035
|
+
toast2.error(t2("auth.externalLoginRequired"));
|
|
5036
|
+
return;
|
|
5037
|
+
}
|
|
5029
5038
|
toast2.error(
|
|
5030
5039
|
error?.response?.data?.error || error?.message || t2(fallbackKey)
|
|
5031
5040
|
);
|
|
@@ -31908,6 +31917,7 @@ export {
|
|
|
31908
31917
|
DialogPortal,
|
|
31909
31918
|
DialogTitle,
|
|
31910
31919
|
DialogTrigger,
|
|
31920
|
+
DocsLink,
|
|
31911
31921
|
DropdownMenu,
|
|
31912
31922
|
DropdownMenuCheckboxItem,
|
|
31913
31923
|
DropdownMenuContent,
|
package/dist/host-commands.js
CHANGED
|
@@ -17,7 +17,7 @@ export function execCommand(client, command, timeoutMs = 30000) {
|
|
|
17
17
|
if (!settled) {
|
|
18
18
|
settled = true;
|
|
19
19
|
cleanup();
|
|
20
|
-
reject(new Error(`Command timeout after ${timeoutMs}ms
|
|
20
|
+
reject(new Error(`Command timeout after ${timeoutMs}ms`));
|
|
21
21
|
}
|
|
22
22
|
}, timeoutMs);
|
|
23
23
|
const cleanup = () => {
|
package/dist/manifest.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* "permissionGroups" used to validate clean and be silently dropped, which
|
|
10
10
|
* made a manifest look like it declared something it did not.
|
|
11
11
|
*/
|
|
12
|
+
import { type PluginEnvVar } from "./docs.js";
|
|
13
|
+
export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDocsUrl, pluginEnvVars, type PluginEnvVar, } from "./docs.js";
|
|
12
14
|
/**
|
|
13
15
|
* The plugin API this build implements. A minor bump adds to the API and
|
|
14
16
|
* never removes; a major bump may break plugins.
|
|
@@ -17,7 +19,7 @@
|
|
|
17
19
|
* "^1.2" needs 1.2 or later). engine.termix is checked against the core
|
|
18
20
|
* version by the server.
|
|
19
21
|
*/
|
|
20
|
-
export declare const PLUGIN_API_VERSION = "1.
|
|
22
|
+
export declare const PLUGIN_API_VERSION = "1.2.0";
|
|
21
23
|
/** The API major, the default engine.api for a new plugin. */
|
|
22
24
|
export declare const SUPPORTED_PLUGIN_API_VERSION: string;
|
|
23
25
|
/** Whether this build's plugin API satisfies a manifest's engine.api. */
|
|
@@ -425,6 +427,10 @@ export interface PluginManifest {
|
|
|
425
427
|
video?: string;
|
|
426
428
|
/** Short lines listing what the plugin does, shown on its page. */
|
|
427
429
|
features?: string[];
|
|
430
|
+
/** Where the plugin's docs live. https only. */
|
|
431
|
+
docs?: string;
|
|
432
|
+
/** Environment variables the plugin reads. */
|
|
433
|
+
env?: PluginEnvVar[];
|
|
428
434
|
engine: PluginEngine;
|
|
429
435
|
/** Catalog capability ids. */
|
|
430
436
|
capabilities: string[];
|
package/dist/manifest.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import semver from "semver";
|
|
13
13
|
import { isKnownCapability } from "./capabilities.js";
|
|
14
|
+
import { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsUrl, } from "./docs.js";
|
|
15
|
+
export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDocsUrl, pluginEnvVars, } from "./docs.js";
|
|
14
16
|
/**
|
|
15
17
|
* The plugin API this build implements. A minor bump adds to the API and
|
|
16
18
|
* never removes; a major bump may break plugins.
|
|
@@ -19,7 +21,7 @@ import { isKnownCapability } from "./capabilities.js";
|
|
|
19
21
|
* "^1.2" needs 1.2 or later). engine.termix is checked against the core
|
|
20
22
|
* version by the server.
|
|
21
23
|
*/
|
|
22
|
-
export const PLUGIN_API_VERSION = "1.
|
|
24
|
+
export const PLUGIN_API_VERSION = "1.2.0";
|
|
23
25
|
/** The API major, the default engine.api for a new plugin. */
|
|
24
26
|
export const SUPPORTED_PLUGIN_API_VERSION = String(semver.major(PLUGIN_API_VERSION));
|
|
25
27
|
/** Whether this build's plugin API satisfies a manifest's engine.api. */
|
|
@@ -207,6 +209,8 @@ const ALLOWED_TOP_LEVEL = new Set([
|
|
|
207
209
|
"icon",
|
|
208
210
|
"video",
|
|
209
211
|
"features",
|
|
212
|
+
"docs",
|
|
213
|
+
"env",
|
|
210
214
|
"dependencies",
|
|
211
215
|
"optionalDependencies",
|
|
212
216
|
"provides",
|
|
@@ -337,6 +341,10 @@ export function validateManifest(manifest) {
|
|
|
337
341
|
errors.push(`Field "video" must be a YouTube link such as https://www.youtube.com/watch?v=..., got: ${JSON.stringify(m.video)}`);
|
|
338
342
|
}
|
|
339
343
|
validateFeatures(m.features, errors);
|
|
344
|
+
if ("docs" in m && pluginDocsUrl(m.docs) === null) {
|
|
345
|
+
errors.push(`Field "docs" must be an https URL, got: ${JSON.stringify(m.docs)}`);
|
|
346
|
+
}
|
|
347
|
+
validateEnv(m.env, errors);
|
|
340
348
|
for (const field of ["backend", "frontend", "locales"]) {
|
|
341
349
|
if (field in m && requireString(m[field], field, errors)) {
|
|
342
350
|
requireRelativePath(m[field], field, errors);
|
|
@@ -379,6 +387,45 @@ function validateFeatures(features, errors) {
|
|
|
379
387
|
}
|
|
380
388
|
});
|
|
381
389
|
}
|
|
390
|
+
function validateEnv(env, errors) {
|
|
391
|
+
if (env === undefined)
|
|
392
|
+
return;
|
|
393
|
+
if (!Array.isArray(env)) {
|
|
394
|
+
errors.push('Field "env" must be an array');
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const seen = new Set();
|
|
398
|
+
env.forEach((entry, i) => {
|
|
399
|
+
const where = `env[${i}]`;
|
|
400
|
+
if (!isPlainObject(entry)) {
|
|
401
|
+
errors.push(`Field "${where}" must be an object`);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
rejectUnknown(entry, ["name", "description", "default", "required", "secret"], where, errors);
|
|
405
|
+
if (typeof entry.name !== "string" || !ENV_NAME_PATTERN.test(entry.name)) {
|
|
406
|
+
errors.push(`Field "${where}.name" must be an uppercase name like MY_PLUGIN_URL, got: ${JSON.stringify(entry.name)}`);
|
|
407
|
+
}
|
|
408
|
+
else if (seen.has(entry.name)) {
|
|
409
|
+
errors.push(`Field "${where}.name" repeats ${entry.name}`);
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
seen.add(entry.name);
|
|
413
|
+
}
|
|
414
|
+
if (typeof entry.description !== "string" ||
|
|
415
|
+
entry.description.trim().length === 0 ||
|
|
416
|
+
entry.description.length > MAX_ENV_DESCRIPTION_LENGTH) {
|
|
417
|
+
errors.push(`Field "${where}.description" must be a non-empty string of at most ${MAX_ENV_DESCRIPTION_LENGTH} characters`);
|
|
418
|
+
}
|
|
419
|
+
if ("default" in entry && typeof entry.default !== "string") {
|
|
420
|
+
errors.push(`Field "${where}.default" must be a string`);
|
|
421
|
+
}
|
|
422
|
+
for (const flag of ["required", "secret"]) {
|
|
423
|
+
if (flag in entry && typeof entry[flag] !== "boolean") {
|
|
424
|
+
errors.push(`Field "${where}.${flag}" must be true or false`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
382
429
|
function validateAuthor(author, errors) {
|
|
383
430
|
if (author === undefined)
|
|
384
431
|
return;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an OpenAPI spec from the @openapi JSDoc blocks above routes. Core and
|
|
3
|
+
* every plugin use this, so the docs site renders them all the same way.
|
|
4
|
+
*/
|
|
5
|
+
export interface OpenApiTag {
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BuildOpenApiOptions {
|
|
10
|
+
title: string;
|
|
11
|
+
version: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Source files or globs holding @openapi blocks. */
|
|
14
|
+
files: string[];
|
|
15
|
+
tags?: OpenApiTag[];
|
|
16
|
+
}
|
|
17
|
+
export type OpenApiSpec = Record<string, unknown> & {
|
|
18
|
+
paths?: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
/** How every Termix route is signed in to. */
|
|
21
|
+
export declare const TERMIX_SECURITY_SCHEMES: {
|
|
22
|
+
readonly bearerAuth: {
|
|
23
|
+
readonly type: "http";
|
|
24
|
+
readonly scheme: "bearer";
|
|
25
|
+
readonly bearerFormat: "JWT";
|
|
26
|
+
readonly description: "Session token sent in the Authorization header as Bearer and the token.";
|
|
27
|
+
};
|
|
28
|
+
readonly cookieAuth: {
|
|
29
|
+
readonly type: "apiKey";
|
|
30
|
+
readonly in: "cookie";
|
|
31
|
+
readonly name: "jwt";
|
|
32
|
+
readonly description: "Session JWT cookie set at sign-in. When present, it takes precedence over the Authorization header.";
|
|
33
|
+
};
|
|
34
|
+
readonly apiKeyAuth: {
|
|
35
|
+
readonly type: "http";
|
|
36
|
+
readonly scheme: "bearer";
|
|
37
|
+
readonly bearerFormat: "API key starting with tmx_";
|
|
38
|
+
readonly description: "API key sent in the Authorization header as Bearer and the key, which starts with tmx_. It acts as the key owner and cannot act as anyone else.";
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export declare function buildOpenApi(options: BuildOpenApiOptions): Promise<OpenApiSpec>;
|
|
42
|
+
/** Whether a spec documents any route. */
|
|
43
|
+
export declare function hasOpenApiPaths(spec: OpenApiSpec): boolean;
|
package/dist/openapi.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an OpenAPI spec from the @openapi JSDoc blocks above routes. Core and
|
|
3
|
+
* every plugin use this, so the docs site renders them all the same way.
|
|
4
|
+
*/
|
|
5
|
+
import swaggerJSDoc from "@deadendjs/swagger-jsdoc";
|
|
6
|
+
/** How every Termix route is signed in to. */
|
|
7
|
+
export const TERMIX_SECURITY_SCHEMES = {
|
|
8
|
+
bearerAuth: {
|
|
9
|
+
type: "http",
|
|
10
|
+
scheme: "bearer",
|
|
11
|
+
bearerFormat: "JWT",
|
|
12
|
+
description: "Session token sent in the Authorization header as Bearer and the token.",
|
|
13
|
+
},
|
|
14
|
+
cookieAuth: {
|
|
15
|
+
type: "apiKey",
|
|
16
|
+
in: "cookie",
|
|
17
|
+
name: "jwt",
|
|
18
|
+
description: "Session JWT cookie set at sign-in. When present, it takes precedence over the Authorization header.",
|
|
19
|
+
},
|
|
20
|
+
apiKeyAuth: {
|
|
21
|
+
type: "http",
|
|
22
|
+
scheme: "bearer",
|
|
23
|
+
bearerFormat: "API key starting with tmx_",
|
|
24
|
+
description: "API key sent in the Authorization header as Bearer and the key, which starts with tmx_. It acts as the key owner and cannot act as anyone else.",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
export async function buildOpenApi(options) {
|
|
28
|
+
const spec = (await swaggerJSDoc({
|
|
29
|
+
definition: {
|
|
30
|
+
openapi: "3.0.3",
|
|
31
|
+
info: {
|
|
32
|
+
title: options.title,
|
|
33
|
+
version: options.version,
|
|
34
|
+
...(options.description ? { description: options.description } : {}),
|
|
35
|
+
},
|
|
36
|
+
servers: [{ url: "/", description: "Your Termix server" }],
|
|
37
|
+
components: {
|
|
38
|
+
securitySchemes: TERMIX_SECURITY_SCHEMES,
|
|
39
|
+
schemas: {
|
|
40
|
+
Error: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
error: { type: "string" },
|
|
44
|
+
details: { type: "string" },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
security: [{ bearerAuth: [] }, { cookieAuth: [] }, { apiKeyAuth: [] }],
|
|
50
|
+
...(options.tags?.length ? { tags: options.tags } : {}),
|
|
51
|
+
},
|
|
52
|
+
apis: options.files.map((f) => f.replace(/\\/g, "/")),
|
|
53
|
+
failOnErrors: true,
|
|
54
|
+
}));
|
|
55
|
+
return spec;
|
|
56
|
+
}
|
|
57
|
+
/** Whether a spec documents any route. */
|
|
58
|
+
export function hasOpenApiPaths(spec) {
|
|
59
|
+
return Object.keys(spec.paths ?? {}).length > 0;
|
|
60
|
+
}
|
package/dist/testing/setup.js
CHANGED
|
@@ -77,6 +77,7 @@ const noop = () => { };
|
|
|
77
77
|
const offline = () => Promise.reject(new Error("No plugin API in a unit test; mock it"));
|
|
78
78
|
globalThis.__termixTestPluginHost = {
|
|
79
79
|
usePluginId: () => "test-plugin",
|
|
80
|
+
useDocsUrl: () => null,
|
|
80
81
|
useTranslation: () => ({
|
|
81
82
|
t: (key) => key,
|
|
82
83
|
language: "en",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@termix-ssh/plugin-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "The contract between Termix core and a plugin: types, the capability catalog and the manifest schema.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -53,6 +53,14 @@
|
|
|
53
53
|
"types": "./dist/changelog.d.ts",
|
|
54
54
|
"default": "./dist/changelog.js"
|
|
55
55
|
},
|
|
56
|
+
"./docs": {
|
|
57
|
+
"types": "./dist/docs.d.ts",
|
|
58
|
+
"default": "./dist/docs.js"
|
|
59
|
+
},
|
|
60
|
+
"./openapi": {
|
|
61
|
+
"types": "./dist/openapi.d.ts",
|
|
62
|
+
"default": "./dist/openapi.js"
|
|
63
|
+
},
|
|
56
64
|
"./settings": {
|
|
57
65
|
"types": "./dist/settings.d.ts",
|
|
58
66
|
"default": "./dist/settings.js"
|
|
@@ -102,6 +110,7 @@
|
|
|
102
110
|
"prepublishOnly": "npm run build"
|
|
103
111
|
},
|
|
104
112
|
"dependencies": {
|
|
113
|
+
"@deadendjs/swagger-jsdoc": "^8.1.2",
|
|
105
114
|
"@tailwindcss/node": "^4.2.4",
|
|
106
115
|
"@tailwindcss/oxide": "^4.2.4",
|
|
107
116
|
"esbuild": "^0.28.1",
|
|
@@ -139,6 +148,18 @@
|
|
|
139
148
|
},
|
|
140
149
|
"@testing-library/react": {
|
|
141
150
|
"optional": true
|
|
151
|
+
},
|
|
152
|
+
"i18next": {
|
|
153
|
+
"optional": true
|
|
154
|
+
},
|
|
155
|
+
"react-dom": {
|
|
156
|
+
"optional": true
|
|
157
|
+
},
|
|
158
|
+
"react-i18next": {
|
|
159
|
+
"optional": true
|
|
160
|
+
},
|
|
161
|
+
"sonner": {
|
|
162
|
+
"optional": true
|
|
142
163
|
}
|
|
143
164
|
},
|
|
144
165
|
"publishConfig": {
|