@highstate/library 0.9.4 → 0.9.6

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/src/network.ts ADDED
@@ -0,0 +1,180 @@
1
+ import { defineEntity, defineUnit, Type, type Static } from "@highstate/contract"
2
+
3
+ export const endpointVisibilitySchema = Type.StringEnum([
4
+ "public", // Reachable from the public internet
5
+ "external", // Reachable from outside the system boundary, but not public
6
+ "internal", // Reachable only from within the system or cluster
7
+ ])
8
+
9
+ export const endpointFilterSchema = Type.Array(endpointVisibilitySchema)
10
+
11
+ export const l3EndpointEntity = defineEntity({
12
+ type: "network.l3-endpoint",
13
+
14
+ schema: Type.Intersect([
15
+ Type.Object({
16
+ visibility: endpointVisibilitySchema,
17
+ metadata: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
18
+ }),
19
+ Type.Union([
20
+ Type.Object({
21
+ type: Type.Literal("hostname"),
22
+
23
+ /**
24
+ * The hostname of the endpoint in the format of a domain name.
25
+ */
26
+ hostname: Type.String(),
27
+ }),
28
+ Type.Object({
29
+ type: Type.Literal("ipv4"),
30
+
31
+ /**
32
+ * The IPv4 address of the endpoint.
33
+ */
34
+ address: Type.String(),
35
+ }),
36
+ Type.Object({
37
+ type: Type.Literal("ipv6"),
38
+
39
+ /**
40
+ * The IPv6 address of the endpoint.
41
+ */
42
+ address: Type.String(),
43
+ }),
44
+ ]),
45
+ ]),
46
+
47
+ meta: {
48
+ color: "#4CAF50",
49
+ description: "The L3 endpoint for some service. May be a domain name or an IP address.",
50
+ },
51
+ })
52
+
53
+ export const l4ProtocolSchema = Type.StringEnum(["tcp", "udp"])
54
+
55
+ export const portInfoSchema = Type.Object({
56
+ port: Type.Number(),
57
+ protocol: l4ProtocolSchema,
58
+ })
59
+
60
+ export const l4EndpointEntity = defineEntity({
61
+ type: "network.l4-endpoint",
62
+
63
+ schema: Type.Intersect([l3EndpointEntity.schema, portInfoSchema]),
64
+
65
+ meta: {
66
+ color: "#2196F3",
67
+ description: "The L4 endpoint for some service. Extends an L3 endpoint with a port.",
68
+ },
69
+ })
70
+
71
+ export const l3Endpoint = defineUnit({
72
+ type: "network.l3-endpoint",
73
+
74
+ args: {
75
+ /**
76
+ * The string representation of the endpoint.
77
+ *
78
+ * May be a domain name or an IP address.
79
+ */
80
+ endpoint: Type.String(),
81
+
82
+ /**
83
+ * The visibility of the endpoint.
84
+ */
85
+ visibility: Type.Default(endpointVisibilitySchema, "public"),
86
+ },
87
+
88
+ outputs: {
89
+ endpoint: l3EndpointEntity,
90
+ },
91
+
92
+ meta: {
93
+ displayName: "L3 Endpoint",
94
+ description: "An L3 endpoint for some service. May be a domain name or an IP address.",
95
+ primaryIcon: "mdi:network-outline",
96
+ primaryIconColor: "#4CAF50",
97
+ defaultNamePrefix: "endpoint",
98
+ category: "Network",
99
+ },
100
+
101
+ source: {
102
+ package: "@highstate/common",
103
+ path: "units/network/l3-endpoint",
104
+ },
105
+ })
106
+
107
+ export const l4Endpoint = defineUnit({
108
+ type: "network.l4-endpoint",
109
+
110
+ args: {
111
+ /**
112
+ * The string representation of the endpoint.
113
+ *
114
+ * May be a domain name or an IP address + port/protocol.
115
+ *
116
+ * The possible formats are:
117
+ *
118
+ * - `endpoint:port` (TCP by default)
119
+ * - `tcp://endpoint:port`
120
+ * - `udp://endpoint:port`
121
+ */
122
+ endpoint: Type.String(),
123
+
124
+ /**
125
+ * The visibility of the endpoint.
126
+ */
127
+ visibility: Type.Default(endpointVisibilitySchema, "public"),
128
+ },
129
+
130
+ outputs: {
131
+ endpoint: l4EndpointEntity,
132
+ },
133
+
134
+ meta: {
135
+ displayName: "L4 Endpoint",
136
+ description: "An L4 endpoint for some service. Extends an L3 endpoint with a port.",
137
+ primaryIcon: "mdi:network-outline",
138
+ primaryIconColor: "#2196F3",
139
+ defaultNamePrefix: "endpoint",
140
+ category: "Network",
141
+ },
142
+
143
+ source: {
144
+ package: "@highstate/common",
145
+ path: "units/network/l4-endpoint",
146
+ },
147
+ })
148
+
149
+ /**
150
+ * The generic visibility of an endpoint.
151
+ *
152
+ * - `public`: Reachable from the public internet.
153
+ * - `external`: Reachable from outside the system boundary (e.g., LAN, VPC), but not public.
154
+ * - `internal`: Reachable only from within the application or infrastructure boundary (e.g., within a cluster).
155
+ */
156
+ export type EndpointVisibility = Static<typeof endpointVisibilitySchema>
157
+
158
+ /**
159
+ * Filter values used to select relevant endpoints based on visibility.
160
+ *
161
+ * - `public`: Only endpoints exposed to the public internet.
162
+ * - `private`: Endpoints not publicly accessible (external + internal).
163
+ * - `external`: Reachable from outside the system but not public (e.g., LAN, VPC).
164
+ * - `internal`: Reachable only from within the system boundary (e.g., inside a cluster).
165
+ * - `most`: Select the most widely accessible endpoints, preferring visibility in the following order: `public` > `external` > `internal`.
166
+ * - If any public endpoints exist, all public endpoints are selected.
167
+ * - Otherwise, if any external endpoints exist, all external endpoints are selected.
168
+ * - If neither exist, all internal endpoints are selected.
169
+ */
170
+ export type EndpointFilter = Static<typeof endpointFilterSchema>
171
+
172
+ export type L3Endpoint = Static<typeof l3EndpointEntity.schema>
173
+ export type L4Endpoint = Static<typeof l4EndpointEntity.schema>
174
+ export type L4Protocol = Static<typeof l4ProtocolSchema>
175
+ export type L4PortInfo = Static<typeof portInfoSchema>
176
+
177
+ /**
178
+ * The L3 or L4 endpoint for some service.
179
+ */
180
+ export type L34Endpoint = (L3Endpoint & { port?: undefined; protocol?: undefined }) | L4Endpoint
package/src/nixos.ts CHANGED
@@ -40,6 +40,7 @@ export const inlineModule = defineUnit({
40
40
  primaryIcon: "simple-icons:nixos",
41
41
  primaryIconColor: "#7ebae4",
42
42
  secondaryIcon: "mdi:file-code",
43
+ category: "NixOS",
43
44
  },
44
45
 
45
46
  source: {
@@ -80,6 +81,7 @@ export const remoteFlake = defineUnit({
80
81
  primaryIconColor: "#7ebae4",
81
82
  secondaryIcon: "simple-icons:git",
82
83
  secondaryIconColor: "#f1502f",
84
+ category: "NixOS",
83
85
  },
84
86
 
85
87
  source: {
@@ -123,6 +125,7 @@ export const inlineFlake = defineUnit({
123
125
  primaryIcon: "simple-icons:nixos",
124
126
  primaryIconColor: "#7ebae4",
125
127
  secondaryIcon: "mdi:file-code",
128
+ category: "NixOS",
126
129
  },
127
130
 
128
131
  source: {
@@ -158,6 +161,7 @@ export const system = defineUnit({
158
161
  primaryIcon: "simple-icons:nixos",
159
162
  primaryIconColor: "#7ebae4",
160
163
  secondaryIcon: "codicon:vm",
164
+ category: "NixOS",
161
165
  },
162
166
 
163
167
  source: {
@@ -1 +1,2 @@
1
+ export * from "./shared"
1
2
  export * as phantun from "./phantun"
@@ -10,6 +10,7 @@ export const deobfuscator = defineUnit({
10
10
  description: "The Phantun Deobfuscator deployed on Kubernetes.",
11
11
  primaryIcon: "mdi:network-outline",
12
12
  secondaryIcon: "mdi:hide",
13
+ category: "Obfuscators",
13
14
  },
14
15
 
15
16
  source: {
@@ -27,6 +28,7 @@ export const obfuscator = defineUnit({
27
28
  description: "The Phantun Obfuscator deployed on Kubernetes.",
28
29
  primaryIcon: "mdi:network-outline",
29
30
  secondaryIcon: "mdi:hide",
31
+ category: "Obfuscators",
30
32
  },
31
33
 
32
34
  source: {
@@ -1,9 +1,16 @@
1
- import { Type } from "@sinclair/typebox"
1
+ import { Type, type Static, type TObject } from "@highstate/contract"
2
2
  import { clusterEntity } from "../k8s"
3
- import { l4EndpointEntity } from "../common"
3
+ import { l4EndpointEntity } from "../network"
4
4
 
5
5
  export const deobfuscatorSpec = {
6
6
  args: {
7
+ /**
8
+ * The name of the namespace and deployment to deploy the deobfuscator on.
9
+ *
10
+ * By default, calculated as `deobfs-{type}-{name}`.
11
+ */
12
+ appName: Type.Optional(Type.String()),
13
+
7
14
  /**
8
15
  * The L4 endpoint to forward deobfuscated traffic to.
9
16
  *
@@ -11,7 +18,16 @@ export const deobfuscatorSpec = {
11
18
  *
12
19
  * @schema
13
20
  */
14
- targetEndpoint: Type.Optional(Type.String()),
21
+ targetEndpoints: Type.Default(Type.Array(Type.String()), []),
22
+
23
+ /**
24
+ * Whether to expose the deobfuscator service by "NodePort" or "LoadBalancer".
25
+ *
26
+ * By default, the service is not exposed and only accessible from within the cluster.
27
+ *
28
+ * @schema
29
+ */
30
+ external: Type.Default(Type.Boolean(), false),
15
31
  },
16
32
 
17
33
  inputs: {
@@ -23,33 +39,59 @@ export const deobfuscatorSpec = {
23
39
  k8sCluster: clusterEntity,
24
40
 
25
41
  /**
26
- * The L4 endpoint to forward deobfuscated traffic to.
42
+ * The L4 endpoints to forward deobfuscated traffic to.
43
+ *
44
+ * Will select the most appropriate endpoint based on the environment.
27
45
  *
28
46
  * @schema
29
47
  */
30
- targetEndpoint: l4EndpointEntity,
48
+ targetEndpoints: {
49
+ entity: l4EndpointEntity,
50
+ required: false,
51
+ multiple: true,
52
+ },
31
53
  },
32
54
 
33
55
  outputs: {
34
56
  /**
35
- * The L4 endpoint of the deobfuscator accepting obfuscated traffic.
57
+ * The L4 endpoints of the deobfuscator accepting obfuscated traffic.
36
58
  *
37
59
  * @schema
38
60
  */
39
- endpoint: l4EndpointEntity,
61
+ endpoints: {
62
+ entity: l4EndpointEntity,
63
+ required: false,
64
+ multiple: true,
65
+ },
40
66
  },
41
- }
67
+ } as const
42
68
 
43
69
  export const obfuscatorSpec = {
44
70
  args: {
71
+ /**
72
+ * The name of the namespace and deployment to deploy the obfuscator on.
73
+ *
74
+ * By default, calculated as `obfs-{type}-{name}`.
75
+ */
76
+ appName: Type.Optional(Type.String()),
77
+
45
78
  /**
46
79
  * The endpoint of the deobfuscator to pass obfuscated traffic to.
47
80
  *
48
- * Will take precedence over the `l4Endpoint` input.
81
+ * Will take precedence over the `endpoint` input.
82
+ *
83
+ * @schema
84
+ */
85
+ endpoints: Type.Default(Type.Array(Type.String()), []),
86
+
87
+ /**
88
+ * Whether to expose the obfuscator service by "NodePort" or "LoadBalancer".
89
+ *
90
+ * By default, the service is not exposed and only accessible from within the cluster.
49
91
  *
50
92
  * @schema
51
93
  */
52
- endpoint: Type.Optional(Type.String()),
94
+ external: Type.Default(Type.Boolean(), false),
53
95
  },
54
96
 
55
97
  inputs: {
@@ -61,22 +103,31 @@ export const obfuscatorSpec = {
61
103
  k8sCluster: clusterEntity,
62
104
 
63
105
  /**
64
- * The L4 endpoint of the deobfuscator to pass obfuscated traffic to.
106
+ * The L4 endpoints of the deobfuscator to pass obfuscated traffic to.
107
+ *
108
+ * Will select the most appropriate endpoint based on the environment.
65
109
  *
66
110
  * @schema
67
111
  */
68
- endpoint: {
112
+ endpoints: {
69
113
  entity: l4EndpointEntity,
70
114
  required: false,
115
+ multiple: true,
71
116
  },
72
117
  },
73
118
 
74
119
  outputs: {
75
120
  /**
76
- * The L4 endpoint accepting unobfuscated traffic.
121
+ * The L4 endpoints accepting unobfuscated traffic.
77
122
  *
78
123
  * @schema
79
124
  */
80
- entryEndpoint: l4EndpointEntity,
125
+ entryEndpoints: {
126
+ entity: l4EndpointEntity,
127
+ multiple: true,
128
+ },
81
129
  },
82
- }
130
+ } as const
131
+
132
+ export type DeobfuscatorArgs = Static<TObject<(typeof deobfuscatorSpec)["args"]>>
133
+ export type ObfuscatorArgs = Static<TObject<(typeof obfuscatorSpec)["args"]>>
package/src/proxmox.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { defineEntity, defineUnit, Type } from "@highstate/contract"
2
- import { serverEntity } from "./common"
2
+ import { serverOutputs } from "./common"
3
3
  import { keyPairEntity } from "./ssh"
4
4
 
5
5
  export const clusterEntity = defineEntity({
@@ -61,7 +61,6 @@ export const connection = defineUnit({
61
61
  category: "Proxmox",
62
62
  primaryIcon: "simple-icons:proxmox",
63
63
  primaryIconColor: "#e56901",
64
- secondaryIcon: "codicon:vm",
65
64
  },
66
65
 
67
66
  source: {
@@ -110,6 +109,10 @@ export const existingImage = defineUnit({
110
109
  id: Type.String(),
111
110
  },
112
111
 
112
+ inputs: {
113
+ proxmoxCluster: clusterEntity,
114
+ },
115
+
113
116
  outputs: {
114
117
  image: imageEntity,
115
118
  },
@@ -154,6 +157,10 @@ export const virtualMachine = defineUnit({
154
157
  waitForAgent: Type.Optional(Type.Boolean({ default: true })),
155
158
  },
156
159
 
160
+ secrets: {
161
+ sshPassword: Type.Optional(Type.String()),
162
+ },
163
+
157
164
  inputs: {
158
165
  proxmoxCluster: clusterEntity,
159
166
  image: imageEntity,
@@ -164,13 +171,7 @@ export const virtualMachine = defineUnit({
164
171
  },
165
172
  },
166
173
 
167
- secrets: {
168
- sshPassword: Type.Optional(Type.String()),
169
- },
170
-
171
- outputs: {
172
- server: serverEntity,
173
- },
174
+ outputs: serverOutputs,
174
175
 
175
176
  meta: {
176
177
  displayName: "Proxmox Virtual Machine",
package/src/restic.ts CHANGED
@@ -5,7 +5,7 @@ export const repoEntity = defineEntity({
5
5
 
6
6
  schema: Type.Object({
7
7
  password: Type.String(),
8
- remoteDomains: Type.Array(Type.String()),
8
+ remoteEndpoints: Type.Array(Type.String()),
9
9
 
10
10
  type: Type.Literal("rclone"),
11
11
  rcloneConfig: Type.String(),
@@ -40,6 +40,7 @@ export const repo = defineUnit({
40
40
  description: "Holds the configuration for a Restic repository and its remote storage.",
41
41
  primaryIconColor: "#e56901",
42
42
  primaryIcon: "material-symbols:backup",
43
+ category: "Infrastructure",
43
44
  },
44
45
 
45
46
  source: {
package/src/sops.ts CHANGED
@@ -24,6 +24,7 @@ export const secrets = defineUnit({
24
24
  displayName: "SOPS Secrets",
25
25
  description: "Encrypts secrets using SOPS for the specified servers.",
26
26
  primaryIcon: "mdi:file-lock",
27
+ category: "Secrets",
27
28
  },
28
29
 
29
30
  source: {
package/src/ssh.ts CHANGED
@@ -1,18 +1,16 @@
1
1
  import { defineEntity, defineUnit, Type, type Static } from "@highstate/contract"
2
+ import { l4EndpointEntity } from "./network"
2
3
 
3
- export const keyTypeSchema = Type.Union([
4
- //
5
- Type.Literal("rsa"),
6
- Type.Literal("ed25519"),
7
- ])
4
+ export const keyTypeSchema = Type.StringEnum(["ed25519"])
8
5
 
9
6
  export const keyPairEntity = defineEntity({
10
7
  type: "ssh.key-pair",
11
8
 
12
9
  schema: Type.Object({
13
10
  type: keyTypeSchema,
14
- privateKey: Type.String(),
11
+ fingerprint: Type.String(),
15
12
  publicKey: Type.String(),
13
+ privateKey: Type.String(),
16
14
  }),
17
15
 
18
16
  meta: {
@@ -21,11 +19,11 @@ export const keyPairEntity = defineEntity({
21
19
  })
22
20
 
23
21
  export const credentialsSchema = Type.Object({
24
- endpoint: Type.Optional(Type.String()),
25
- user: Type.Optional(Type.String()),
26
- port: Type.Optional(Type.Number()),
22
+ endpoints: Type.Array(l4EndpointEntity.schema),
23
+ hostKey: Type.String(),
24
+ user: Type.String(),
27
25
  password: Type.Optional(Type.String()),
28
- privateKey: Type.Optional(Type.String()),
26
+ keyPair: Type.Optional(keyPairEntity.schema),
29
27
  })
30
28
 
31
29
  export const keyPair = defineUnit({
@@ -51,7 +49,7 @@ export const keyPair = defineUnit({
51
49
 
52
50
  source: {
53
51
  package: "@highstate/common",
54
- path: "ssh/key-pair",
52
+ path: "units/ssh/key-pair",
55
53
  },
56
54
  })
57
55
 
package/src/talos.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import { defineEntity, defineUnit, Type } from "@highstate/contract"
2
- import { serverEntity } from "./common"
3
- import { clusterEntity as k8sClusterEntity, sharedClusterArgs } from "./k8s"
4
- import { providerEntity } from "./dns"
2
+ import { clusterInputs, clusterOutputs, scheduleOnMastersPolicyArgs } from "./k8s"
5
3
 
6
4
  export const clusterEntity = defineEntity({
7
5
  type: "talos.cluster",
@@ -23,25 +21,7 @@ export const cluster = defineUnit({
23
21
  type: "talos.cluster",
24
22
 
25
23
  args: {
26
- /**
27
- * Allow scheduling workloads on the master nodes.
28
- *
29
- * If no workers are specified, this option is ignored and the master nodes are used as workers.
30
- *
31
- * By default, this option is set to false.
32
- *
33
- * @schema
34
- */
35
- scheduleOnMasters: Type.Default(Type.Boolean(), false),
36
-
37
- /**
38
- * The endpoint of the cluster.
39
- *
40
- * By default, the first master node's endpoint is used.
41
- *
42
- * @schema
43
- */
44
- endpoint: Type.Optional(Type.String()),
24
+ ...scheduleOnMastersPolicyArgs,
45
25
 
46
26
  /**
47
27
  * The name of the cluster.
@@ -109,29 +89,12 @@ export const cluster = defineUnit({
109
89
  * By default, this option is set to true.
110
90
  */
111
91
  enableTunDevicePlugin: Type.Default(Type.Boolean(), true),
112
-
113
- ...sharedClusterArgs,
114
92
  },
115
93
 
116
- inputs: {
117
- masters: {
118
- entity: serverEntity,
119
- multiple: true,
120
- },
121
- workers: {
122
- entity: serverEntity,
123
- multiple: true,
124
- required: false,
125
- },
126
- dnsProviders: {
127
- entity: providerEntity,
128
- required: false,
129
- multiple: true,
130
- },
131
- },
94
+ inputs: clusterInputs,
132
95
 
133
96
  outputs: {
134
- k8sCluster: k8sClusterEntity,
97
+ ...clusterOutputs,
135
98
  talosCluster: clusterEntity,
136
99
  },
137
100
 
package/src/timeweb.ts CHANGED
@@ -26,6 +26,7 @@ export const connection = defineUnit({
26
26
  displayName: "Timeweb Connection",
27
27
  description: "Creates a new Timeweb connection.",
28
28
  primaryIcon: "material-symbols:cloud",
29
+ category: "Timeweb",
29
30
  },
30
31
 
31
32
  source: {
@@ -64,6 +65,7 @@ export const virtualMachine = defineUnit({
64
65
  description: "Creates a new Timeweb virtual machine.",
65
66
  primaryIcon: "material-symbols:cloud",
66
67
  secondaryIcon: "codicon:vm",
68
+ category: "Timeweb",
67
69
  },
68
70
 
69
71
  source: {
package/src/utils.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { Type, type Static } from "@highstate/contract"
2
+
3
+ type PrefixWith<TString extends string, TPrefix extends string> = TPrefix extends ""
4
+ ? TString
5
+ : `${TPrefix}${Capitalize<TString>}`
6
+
7
+ function prefixWith<TString extends string, TPrefix extends string>(
8
+ string: TString,
9
+ prefix?: TPrefix,
10
+ ): PrefixWith<TString, TPrefix> {
11
+ return (
12
+ prefix ? `${prefix}${string.charAt(0).toUpperCase()}${string.slice(1)}` : string
13
+ ) as PrefixWith<TString, TPrefix>
14
+ }
15
+
16
+ type PrefixedKeys<T extends Record<string, unknown>, Prefix extends string> = {
17
+ [K in keyof T as PrefixWith<Extract<K, string>, Prefix>]: T[K]
18
+ }
19
+
20
+ export function prefixKeysWith<T extends Record<string, unknown>, Prefix extends string>(
21
+ prefix: Prefix | undefined,
22
+ obj: T,
23
+ ): PrefixedKeys<T, Prefix> {
24
+ return Object.fromEntries(
25
+ Object.entries(obj).map(([key, value]) => [prefixWith(key, prefix), value]),
26
+ ) as PrefixedKeys<T, Prefix>
27
+ }
28
+
29
+ export const arrayPatchModeSchema = Type.StringEnum(["prepend", "replace"])
30
+
31
+ /**
32
+ * The mode to use when patching some array.
33
+ *
34
+ * - `prepend`: Prepend the values of the new array to the existing array.
35
+ * - `replace`: Replace the existing array with the new array.
36
+ */
37
+ export type ArrayPatchMode = Static<typeof arrayPatchModeSchema>