@termix-ssh/plugin-sdk 1.0.12 → 1.0.13

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/PLUGIN-GUIDE.md +91 -59
  3. package/dist/backend.d.ts +404 -0
  4. package/dist/capabilities.js +5 -0
  5. package/dist/db.js +1 -0
  6. package/dist/desktop.d.ts +0 -243
  7. package/dist/frontend.d.ts +23 -2
  8. package/dist/host/{PluginsTab-EV4MSGY6.js → PluginsTab-OXQQ7M4I.js} +511 -178
  9. package/dist/host/{chunk-X4QZKO5G.js → chunk-54KCK6IZ.js} +52 -5
  10. package/dist/host/{chunk-XKA3DBB2.js → chunk-CALNJCHN.js} +114 -54
  11. package/dist/host/{chunk-RUPLD6RF.js → chunk-CN5UBTBP.js} +2 -86
  12. package/dist/host/{chunk-AWR6FYDO.js → chunk-ERGN4YW6.js} +5552 -5550
  13. package/dist/host/{chunk-VEWOYAMZ.js → chunk-T2PZWXFJ.js} +1 -1
  14. package/dist/host/core-classes.json +1 -1
  15. package/dist/host/{linked-server-B4NEG4MA.js → linked-server-5VFO4XQB.js} +1 -1
  16. package/dist/host/{rbac-api-OUO3LUOC.js → rbac-api-5YMBJAO5.js} +1 -1
  17. package/dist/host/testing-host.js +4 -4
  18. package/dist/host/types/src/types/onboarding.d.ts +0 -2
  19. package/dist/host/types/src/ui/api/audit-log-api.d.ts +0 -10
  20. package/dist/host/types/src/ui/api/credentials-api.d.ts +0 -22
  21. package/dist/host/types/src/ui/api/plugins-api.d.ts +4 -0
  22. package/dist/host/types/src/ui/api/settings-api.d.ts +0 -6
  23. package/dist/host/types/src/ui/api/ssh-host-management-api.d.ts +0 -28
  24. package/dist/host/types/src/ui/main-axios.d.ts +2 -2
  25. package/dist/host/types/src/ui/onboarding/onboarding-registry.d.ts +3 -1
  26. package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +5 -6
  27. package/dist/host/types/src/ui/plugins/plugin-model.d.ts +20 -0
  28. package/dist/host/types/src/ui/plugins/use-plugins-manager.d.ts +3 -0
  29. package/dist/host/types/src/ui/sidebar/host-contributions.d.ts +10 -0
  30. package/dist/host/ui.js +14 -205
  31. package/dist/host/{use-permissions-6VSHHUMB.js → use-permissions-ISEDRY3J.js} +1 -1
  32. package/dist/manifest.d.ts +10 -1
  33. package/dist/manifest.js +16 -1
  34. package/dist/ssh-keys.d.ts +29 -0
  35. package/dist/ssh-keys.js +85 -0
  36. package/dist/testing.d.ts +32 -15
  37. package/dist/testing.js +218 -1
  38. package/package.json +5 -1
  39. package/schema/manifest.schema.json +10 -0
  40. package/dist/host/types/src/ui/sidebar/host-export-payload.d.ts +0 -30
package/dist/backend.d.ts CHANGED
@@ -696,6 +696,151 @@ export interface PluginHosts {
696
696
  * Needs hosts:read.
697
697
  */
698
698
  status: PluginHostStatusApi;
699
+ /**
700
+ * The hosts the acting user may connect to (their own and shared ones) as a
701
+ * status provider needs them: address, port and jump hosts, no secrets.
702
+ * Pass hostIds to narrow it. Needs hosts:read.
703
+ */
704
+ probeTargets: (filter?: {
705
+ hostIds?: number[];
706
+ }) => Promise<PluginHostProbeTarget[]>;
707
+ /** Whether a session is open to the host right now. Needs hosts:read. */
708
+ sessionActive: (hostId: number) => boolean;
709
+ /**
710
+ * Imports Termix JSON host rows for the acting user, the same way POST
711
+ * /host/bulk-import does: up to 100 rows, jump hosts remapped by exportId,
712
+ * defaults, protocol logins and plugin settings applied, one save at the end.
713
+ * Needs hosts:write, plus credentials:write when credentials are passed, and
714
+ * the acting user needs the core hosts.create and hosts.edit permissions.
715
+ */
716
+ importMany: (hosts: Record<string, unknown>[], options?: PluginHostImportOptions) => Promise<PluginHostImportResult>;
717
+ /** Imports the Host entries of an OpenSSH config file. Same rules as importMany. */
718
+ importSshConfig: (content: string, options?: Pick<PluginHostImportOptions, "overwrite" | "atomic">) => Promise<PluginHostImportResult>;
719
+ /**
720
+ * The acting user's own hosts as Termix JSON. Without share the secrets are
721
+ * included, decrypted. With share every secret is left out and credential
722
+ * logins point at a scrubbed credentials list by alias. Needs hosts:export
723
+ * and is always audited.
724
+ */
725
+ exportMany: (options?: {
726
+ share?: boolean;
727
+ /** Only these of the user's hosts. */
728
+ hostIds?: number[];
729
+ }) => Promise<PluginHostExport>;
730
+ /**
731
+ * Validates and writes this plugin's own host settings from an imported
732
+ * row. Called for every imported row once the host exists. Return the
733
+ * values to write, or null to write nothing. Removed when the plugin
734
+ * deactivates. Needs hosts:write.
735
+ */
736
+ registerImportNormalizer: (normalizer: PluginHostImportNormalizer) => () => void;
737
+ /** The recent activity list on the dashboard. */
738
+ activity: PluginHostActivityApi;
739
+ }
740
+ export interface PluginHostImportOptions {
741
+ /** Update a host that matches on ip, port and username instead of skipping it. */
742
+ overwrite?: boolean;
743
+ /**
744
+ * All or nothing: if any row fails, the hosts this call created are deleted
745
+ * and the result says rolledBack. Cannot be combined with overwrite.
746
+ */
747
+ atomic?: boolean;
748
+ /** Credential placeholders rows can refer to by credentialAlias. */
749
+ credentials?: Array<Record<string, unknown>>;
750
+ }
751
+ export interface PluginHostImportResult {
752
+ success: number;
753
+ updated: number;
754
+ skipped: number;
755
+ failed: number;
756
+ errors: string[];
757
+ createdHostIds: number[];
758
+ rolledBack?: boolean;
759
+ }
760
+ export interface PluginHostExport {
761
+ hosts: Array<Record<string, unknown>>;
762
+ /** Share exports only. */
763
+ version?: string;
764
+ exportedAt?: string;
765
+ credentials?: Array<Record<string, unknown>>;
766
+ }
767
+ export type PluginHostImportNormalizer = (raw: Record<string, unknown>) => Record<string, unknown> | null;
768
+ export interface PluginHostProbeTarget {
769
+ id: number;
770
+ /** The user who owns the host; its jump hosts are theirs. */
771
+ ownerUserId: string;
772
+ ip: string;
773
+ port: number;
774
+ connectionType: string;
775
+ jumpHosts: Array<{
776
+ hostId: number;
777
+ }>;
778
+ statusCheckEnabled: boolean;
779
+ /** Seconds, or null to use the global interval. */
780
+ statusCheckInterval: number | null;
781
+ }
782
+ /**
783
+ * The plugin that owns host status. Core keeps the routes, the sync feed and
784
+ * ctx.hosts.status; this fills them. One provider at a time.
785
+ */
786
+ export interface PluginHostStatusProvider {
787
+ start: () => void;
788
+ stop: () => void;
789
+ get: (hostId: number) => PluginHostStatusEntry | null;
790
+ /**
791
+ * Every status known, after polling is brought in line with the request:
792
+ * with hostIds, exactly those of the user's hosts; without, all of them.
793
+ */
794
+ statusesFor: (userId: string, hostIds: number[] | null) => Promise<Map<number, PluginHostStatusEntry>>;
795
+ /** Restarts the user's checks. */
796
+ refresh: (userId: string) => Promise<void>;
797
+ check: (hostId: number) => Promise<PluginHostStatusEntry | null>;
798
+ reportLogin: (hostId: number, outcome: {
799
+ ok: boolean;
800
+ }) => void;
801
+ registerPort: (connectionType: string, resolve: (hostId: number) => number | undefined | Promise<number | undefined>) => () => void;
802
+ /** The global check interval in seconds. */
803
+ getIntervalSeconds: () => Promise<number>;
804
+ setIntervalSeconds: (seconds: number) => Promise<void>;
805
+ }
806
+ export interface PluginActivityEntry {
807
+ id: number;
808
+ userId: string;
809
+ type: string;
810
+ hostId: number;
811
+ hostName: string | null;
812
+ timestamp: string;
813
+ }
814
+ export type PluginRecordActivityResult = {
815
+ status: "logged";
816
+ id: number;
817
+ } | {
818
+ status: "rate_limited";
819
+ } | {
820
+ status: "invalid_type";
821
+ } | {
822
+ status: "denied";
823
+ } | {
824
+ status: "unavailable";
825
+ };
826
+ /** The plugin that stores recent activity. One provider at a time. */
827
+ export interface PluginActivityProvider {
828
+ record: (userId: string, entry: {
829
+ type: string;
830
+ hostId: number;
831
+ hostName: string;
832
+ }) => Promise<PluginRecordActivityResult>;
833
+ list: (userId: string, limit: number) => Promise<PluginActivityEntry[]>;
834
+ deleteByUserId: (userId: string) => Promise<void>;
835
+ deleteByHostIds: (hostIds: number[]) => Promise<void>;
836
+ }
837
+ export interface PluginHostActivityApi {
838
+ /**
839
+ * Becomes the store behind the dashboard's recent activity and
840
+ * ctx.hosts.recordActivity. Needs hosts:activity-provide. Removed on
841
+ * deactivate.
842
+ */
843
+ provide: (provider: PluginActivityProvider) => () => void;
699
844
  }
700
845
  /**
701
846
  * online: the port answers, a session is open or a login worked. offline: the
@@ -736,6 +881,11 @@ export interface PluginHostStatusApi {
736
881
  * back to the host's port. Removed on deactivate.
737
882
  */
738
883
  registerPort: (connectionType: string, resolve: (hostId: number) => number | undefined | Promise<number | undefined>) => () => void;
884
+ /**
885
+ * Becomes core's host status. Needs hosts:status-provide. Removed on
886
+ * deactivate, which hands status back to core's built-in checks.
887
+ */
888
+ provide: (provider: PluginHostStatusProvider) => () => void;
739
889
  }
740
890
  /**
741
891
  * A host as the SSH pipeline reads it: resolved by core, with secrets filled
@@ -879,6 +1029,23 @@ export interface PluginSshConnectOptions {
879
1029
  */
880
1030
  sock?: unknown;
881
1031
  }
1032
+ export interface PluginSshExecOptions extends PluginSshConnectOptions {
1033
+ /** Time to wait for the command to finish. Default 30s, at most 10 minutes. */
1034
+ timeoutMs?: number;
1035
+ /** Most bytes kept of each of stdout and stderr. Default 256 KB, at most 4 MB. */
1036
+ maxOutputBytes?: number;
1037
+ /** Written to the command's standard input, then closed. */
1038
+ stdin?: string;
1039
+ }
1040
+ export interface PluginSshExecResult {
1041
+ stdout: string;
1042
+ stderr: string;
1043
+ /** The exit code. Null when the command was killed or ran out of time. */
1044
+ code: number | null;
1045
+ /** Output went past maxOutputBytes and the rest was dropped. */
1046
+ truncated: boolean;
1047
+ timedOut: boolean;
1048
+ }
882
1049
  export interface PluginSshConnection<Client = unknown> {
883
1050
  /** An ssh2 Client, already "ready". */
884
1051
  client: Client;
@@ -897,8 +1064,34 @@ export interface PluginSshConnection<Client = unknown> {
897
1064
  * audit line per new connection. Connections still open on deactivate are
898
1065
  * closed.
899
1066
  */
1067
+ export interface PluginNetwork {
1068
+ /**
1069
+ * Whether a TCP port answers. An SSH banner is read and answered politely;
1070
+ * nothing is ever sent that logs in. Loopback, private and link-local
1071
+ * addresses are allowed, since status checks target the user's own hosts.
1072
+ */
1073
+ tcpProbe: (host: string, port: number, options?: {
1074
+ timeoutMs?: number;
1075
+ }) => Promise<boolean>;
1076
+ }
900
1077
  export interface PluginSsh {
1078
+ /**
1079
+ * Whether a TCP port answers through the host's jump host chain. Chains are
1080
+ * shared and closed when idle. The acting user must be able to connect to
1081
+ * the host. Needs ssh:connect.
1082
+ */
1083
+ probe: (hostId: number, options?: {
1084
+ port?: number;
1085
+ timeoutMs?: number;
1086
+ }) => Promise<boolean>;
901
1087
  connect: <Client = unknown>(host: number | PluginSshHost, options?: PluginSshConnectOptions) => Promise<PluginSshConnection<Client>>;
1088
+ /**
1089
+ * Runs one command on a host with its stored login and closes the
1090
+ * connection. The acting user needs connect access to the host, the same as
1091
+ * connect. Output is capped and the command is stopped at the time limit.
1092
+ * Needs ssh:connect and credentials:use.
1093
+ */
1094
+ exec: (host: number | PluginSshHost, command: string, options?: PluginSshExecOptions) => Promise<PluginSshExecResult>;
902
1095
  /** Borrows a pooled connection. The pool key is `<pool>:<owner>:<address>`. */
903
1096
  withConnection: <T, Client = unknown>(host: number | PluginSshHost, options: PluginSshConnectOptions & {
904
1097
  pool: string;
@@ -1348,6 +1541,149 @@ export interface PluginDesktop {
1348
1541
  }>;
1349
1542
  /** Whether the server runs embedded in the desktop app, so the calls above can work. */
1350
1543
  available: () => boolean;
1544
+ /**
1545
+ * The user's own machine. Only works on the desktop app's embedded backend
1546
+ * and needs desktop:local; every call is audited once per plugin start.
1547
+ */
1548
+ readonly local: PluginDesktopLocal;
1549
+ }
1550
+ export interface PluginLocalDirEntry {
1551
+ name: string;
1552
+ path: string;
1553
+ type: "file" | "directory" | "link";
1554
+ size: number;
1555
+ modifiedTimestamp?: number;
1556
+ linkTarget?: string;
1557
+ hidden: boolean;
1558
+ }
1559
+ export interface PluginLocalWalkResult {
1560
+ files: Array<{
1561
+ localPath: string;
1562
+ relativePath: string;
1563
+ size: number;
1564
+ }>;
1565
+ emptyDirs: string[];
1566
+ totalBytes: number;
1567
+ }
1568
+ export interface PluginLocalPty {
1569
+ readonly pid: number;
1570
+ /** The shell program that was started. */
1571
+ readonly shell: string;
1572
+ write: (data: string) => void;
1573
+ resize: (cols: number, rows: number) => void;
1574
+ kill: () => void;
1575
+ onData: (handler: (data: string) => void) => () => void;
1576
+ onExit: (handler: (exitCode: number) => void) => () => void;
1577
+ }
1578
+ /** A download being written next to its final name, published when done. */
1579
+ export interface PluginLocalDownload {
1580
+ /** Final path inside the chosen folder, links inside it already refused. */
1581
+ readonly path: string;
1582
+ readonly stream: NodeJS.WritableStream;
1583
+ /** Moves the finished partial onto its final name. */
1584
+ publish: (options?: {
1585
+ overwrite?: boolean;
1586
+ }) => Promise<string>;
1587
+ /** Removes the partial file. Safe to call after publish. */
1588
+ abort: () => Promise<void>;
1589
+ }
1590
+ export interface PluginLocalResponse {
1591
+ readonly status: number;
1592
+ readonly ok: boolean;
1593
+ readonly headers: {
1594
+ get: (name: string) => string | null;
1595
+ };
1596
+ /** A web stream of the body, or null when there is none. */
1597
+ readonly body: AsyncIterable<Uint8Array> | null;
1598
+ text: () => Promise<string>;
1599
+ }
1600
+ export interface PluginDesktopLocal {
1601
+ /** Whether local access is possible: embedded backend and capability granted. */
1602
+ available: () => boolean;
1603
+ /**
1604
+ * Calls this plugin's own HTTP routes on the embedded backend ("local") or
1605
+ * on the server the desktop is linked to ("remote"), as the acting user.
1606
+ * The path is under /plugin-api/<this plugin id>; nothing else is
1607
+ * reachable. The link's proxy headers and certificate rules apply. A body
1608
+ * may be a string, a buffer or a Node stream.
1609
+ */
1610
+ pluginFetch: (origin: "local" | "remote", subPath: string, init?: {
1611
+ method?: string;
1612
+ headers?: Record<string, string>;
1613
+ body?: string | Buffer | NodeJS.ReadableStream;
1614
+ signal?: AbortSignal;
1615
+ }) => Promise<PluginLocalResponse>;
1616
+ info: () => Promise<{
1617
+ home: string;
1618
+ separator: string;
1619
+ platform: NodeJS.Platform;
1620
+ /** The desktop app's user data folder. */
1621
+ userDataDir: string;
1622
+ /** The port the embedded backend listens on. */
1623
+ backendPort: number;
1624
+ /** The server this desktop is linked to, or null. */
1625
+ link: {
1626
+ serverUrl: string;
1627
+ token: string | null;
1628
+ /**
1629
+ * Headers for a request to the linked server: the session, plus the
1630
+ * proxy headers and basic auth the link was set up with.
1631
+ */
1632
+ headers: Record<string, string>;
1633
+ /** The link accepts a self-signed certificate. */
1634
+ allowInvalidCertificate: boolean;
1635
+ } | null;
1636
+ }>;
1637
+ /**
1638
+ * GET a JSON route on the linked server with the link's session, proxy
1639
+ * headers and certificate rules. Rejects with an error whose `kind` is
1640
+ * "signed_out" when the server refused the session.
1641
+ */
1642
+ linkJson: (pathname: string) => Promise<unknown>;
1643
+ readonly fs: {
1644
+ list: (dirPath: string) => Promise<{
1645
+ path: string;
1646
+ parent: string | null;
1647
+ entries: PluginLocalDirEntry[];
1648
+ }>;
1649
+ mkdir: (parentPath: string, name: string) => Promise<string>;
1650
+ createFile: (parentPath: string, name: string) => Promise<string>;
1651
+ /** Renames inside the same folder; never replaces an existing name. */
1652
+ rename: (path: string, newName: string) => Promise<string>;
1653
+ /** Creates a folder; with rootPath it must stay inside that folder. */
1654
+ ensureDir: (dirPath: string, rootPath?: string) => Promise<string>;
1655
+ /** Which of the given paths exist. */
1656
+ exists: (paths: string[]) => Promise<string[]>;
1657
+ walk: (rootPaths: string[]) => Promise<PluginLocalWalkResult>;
1658
+ /** Sends entries to the operating system's trash. */
1659
+ trash: (paths: string[]) => Promise<{
1660
+ trashed: number;
1661
+ failed: Array<{
1662
+ path: string;
1663
+ error: string;
1664
+ }>;
1665
+ }>;
1666
+ reveal: (path: string) => Promise<void>;
1667
+ open: (path: string) => Promise<void>;
1668
+ openRead: (path: string) => Promise<{
1669
+ stream: NodeJS.ReadableStream;
1670
+ size: number;
1671
+ }>;
1672
+ openDownload: (options: {
1673
+ rootPath: string;
1674
+ destPath: string;
1675
+ transferId: string;
1676
+ overwrite?: boolean;
1677
+ }) => Promise<PluginLocalDownload>;
1678
+ };
1679
+ readonly pty: {
1680
+ spawn: (options?: {
1681
+ cols?: number;
1682
+ rows?: number;
1683
+ /** "wsl" on Windows starts WSL instead of PowerShell. */
1684
+ shell?: string;
1685
+ }) => Promise<PluginLocalPty>;
1686
+ };
1351
1687
  }
1352
1688
  /**
1353
1689
  * A host protocol whose login core keeps next to the host: any id a plugin
@@ -1437,6 +1773,23 @@ export interface PluginCredentials {
1437
1773
  * that would provide it.
1438
1774
  */
1439
1775
  registerSecretResolver: (scheme: string, resolve: (userId: string, reference: string) => Promise<string>) => void;
1776
+ /**
1777
+ * The public key line of an SSH key credential the acting user can see
1778
+ * (their own, with the core credentials.view permission). Derived from the
1779
+ * private key when none is stored, including a key kept behind a secret
1780
+ * reference. Null when the credential is missing, is not a key, or cannot
1781
+ * be read. Needs credentials:use. Audited.
1782
+ */
1783
+ publicKey: (credentialId: number) => Promise<string | null>;
1784
+ /**
1785
+ * Replaces secret references ("op://...") in a key and its passphrase with
1786
+ * the real values, for the acting user. Plain values pass through. Hands
1787
+ * private key material to the plugin. Needs credentials:read. Audited.
1788
+ */
1789
+ resolveKeyRefs: (key: string, passphrase?: string | null) => Promise<{
1790
+ key: string;
1791
+ passphrase?: string;
1792
+ }>;
1440
1793
  }
1441
1794
  /**
1442
1795
  * An audit line under an action name of the plugin's choosing (an SSH login),
@@ -1458,6 +1811,55 @@ export interface PluginAudit {
1458
1811
  */
1459
1812
  request?: unknown;
1460
1813
  }) => Promise<void>;
1814
+ /**
1815
+ * Called for every audit line core or any plugin writes, after it is
1816
+ * accepted. Fire and forget: a slow or throwing handler never delays or
1817
+ * fails the audited action. Lines written before the plugin started are not
1818
+ * replayed; read them with list or export. Returns an unsubscribe function;
1819
+ * it is also removed when the plugin deactivates. Needs audit:read.
1820
+ */
1821
+ subscribe: (handler: (entry: PluginAuditEntry) => void) => () => void;
1822
+ /** A page of stored lines, newest first. Needs audit:read. */
1823
+ list: (options?: {
1824
+ filters?: PluginAuditFilters;
1825
+ limit?: number;
1826
+ offset?: number;
1827
+ }) => Promise<{
1828
+ entries: PluginAuditEntry[];
1829
+ total: number;
1830
+ }>;
1831
+ /**
1832
+ * Stored lines in time order, in batches, so an export never holds the
1833
+ * whole trail in memory. Needs audit:read.
1834
+ */
1835
+ exportBatches: (filters?: PluginAuditFilters, batchSize?: number) => AsyncGenerator<PluginAuditEntry[]>;
1836
+ }
1837
+ export interface PluginAuditFilters {
1838
+ userId?: string;
1839
+ action?: string;
1840
+ resourceType?: string;
1841
+ success?: boolean;
1842
+ /** ISO date-time. */
1843
+ startDate?: string;
1844
+ /** ISO date-time. */
1845
+ endDate?: string;
1846
+ }
1847
+ export interface PluginAuditEntry {
1848
+ /** Only on stored lines (list and export). */
1849
+ id?: number;
1850
+ /** ISO date-time. */
1851
+ timestamp: string;
1852
+ userId: string | null;
1853
+ username: string;
1854
+ action: string;
1855
+ resourceType: string;
1856
+ resourceId: string | null;
1857
+ resourceName: string | null;
1858
+ details: string | null;
1859
+ ipAddress: string | null;
1860
+ userAgent: string | null;
1861
+ success: boolean;
1862
+ errorMessage: string | null;
1461
1863
  }
1462
1864
  /** A notification channel a user set up. Its config never leaves the hub. */
1463
1865
  export interface PluginNotificationChannel {
@@ -1785,6 +2187,8 @@ export interface PluginContext {
1785
2187
  readonly notify: PluginNotify;
1786
2188
  /** Outbound HTTP through core's SSRF guard. Needs network:outbound. */
1787
2189
  readonly fetch: PluginFetch;
2190
+ /** Plain reachability checks. Needs network:probe. */
2191
+ readonly network: PluginNetwork;
1788
2192
  /** Programs on the Termix server. Needs process:spawn. */
1789
2193
  readonly process: PluginProcess;
1790
2194
  /** The server certificate. Needs system:tls. */
@@ -37,16 +37,21 @@ export const CAPABILITY_CATALOG = [
37
37
  entry("notify:hub", "high"),
38
38
  entry("ui:layout", "high"),
39
39
  entry("hosts:write", "medium"),
40
+ entry("hosts:export", "high"),
40
41
  entry("credentials:use", "medium"),
41
42
  entry("credentials:write", "medium"),
42
43
  entry("network:outbound", "medium"),
43
44
  entry("network:serve", "medium"),
44
45
  entry("network:broadcast", "medium"),
46
+ entry("network:probe", "medium"),
47
+ entry("hosts:status-provide", "medium"),
48
+ entry("hosts:activity-provide", "medium"),
45
49
  entry("users:read", "medium"),
46
50
  entry("events:core", "medium"),
47
51
  entry("notify:send", "medium"),
48
52
  entry("audit:read", "medium"),
49
53
  entry("desktop:window", "medium"),
54
+ entry("desktop:local", "high"),
50
55
  entry("hosts:read", "low"),
51
56
  entry("db:own", "low"),
52
57
  entry("kv:own", "low"),
package/dist/db.js CHANGED
@@ -160,6 +160,7 @@ export const LEGACY_TABLE_OWNERS = {
160
160
  homepage_items: "homepage",
161
161
  homepage_layouts: "homepage",
162
162
  dashboard_service_links: "homepage",
163
+ recent_activity: "homepage",
163
164
  secret_sources: "secret-sources",
164
165
  opkssh_tokens: "opkssh",
165
166
  vault_profiles: "vault",