@ebowwa/hetzner 0.3.2 → 0.3.3
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/dist/actions.js +782 -0
- package/dist/bootstrap/index.js +1 -0
- package/dist/client.js +1867 -0
- package/dist/errors.js +236 -0
- package/dist/index.js +40 -38
- package/dist/onboarding/index.js +2 -2
- package/dist/pricing.js +587 -0
- package/dist/schemas.js +475 -0
- package/dist/servers.js +688 -0
- package/dist/ssh-keys.js +474 -0
- package/dist/types.js +101 -0
- package/dist/volumes.js +119 -0
- package/package.json +51 -1
- package/dist/actions.d.ts +0 -355
- package/dist/auth.d.ts +0 -6
- package/dist/bootstrap/cloud-init.d.ts +0 -78
- package/dist/bootstrap/firewall.d.ts +0 -118
- package/dist/bootstrap/genesis.d.ts +0 -82
- package/dist/bootstrap/index.d.ts +0 -29
- package/dist/bootstrap/kernel-hardening.d.ts +0 -69
- package/dist/bootstrap/security-audit.d.ts +0 -45
- package/dist/bootstrap/ssh-hardening.d.ts +0 -67
- package/dist/client.d.ts +0 -62
- package/dist/config.d.ts +0 -4
- package/dist/cpufeatures-mvwrkyaq.node +0 -0
- package/dist/errors.d.ts +0 -170
- package/dist/index.d.ts +0 -21
- package/dist/onboarding/claude.d.ts +0 -37
- package/dist/onboarding/cpufeatures-mvwrkyaq.node +0 -0
- package/dist/onboarding/doppler.d.ts +0 -37
- package/dist/onboarding/git.d.ts +0 -38
- package/dist/onboarding/index.d.ts +0 -19
- package/dist/onboarding/onboarding.d.ts +0 -41
- package/dist/onboarding/sshcrypto-6mayxj08.node +0 -0
- package/dist/onboarding/tailscale.d.ts +0 -38
- package/dist/onboarding/types.d.ts +0 -111
- package/dist/pricing.d.ts +0 -330
- package/dist/schemas.d.ts +0 -6629
- package/dist/server-status.d.ts +0 -25
- package/dist/servers.d.ts +0 -164
- package/dist/ssh-keys.d.ts +0 -35
- package/dist/ssh-setup.d.ts +0 -47
- package/dist/sshcrypto-6mayxj08.node +0 -0
- package/dist/types.d.ts +0 -303
- package/dist/volumes.d.ts +0 -105
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,587 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = import.meta.require;
|
|
19
|
+
|
|
20
|
+
// src/schemas.ts
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
import {
|
|
23
|
+
EnvironmentStatus,
|
|
24
|
+
ActionStatus,
|
|
25
|
+
VolumeStatus
|
|
26
|
+
} from "@ebowwa/codespaces-types/compile";
|
|
27
|
+
var ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
28
|
+
var ipv6Regex = /^[0-9a-fA-F:]+(?:\/\d{1,3})?$/;
|
|
29
|
+
var ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
30
|
+
var HetznerErrorSchema = z.object({
|
|
31
|
+
code: z.string(),
|
|
32
|
+
message: z.string(),
|
|
33
|
+
details: z.any().optional()
|
|
34
|
+
});
|
|
35
|
+
var HetznerPaginationSchema = z.object({
|
|
36
|
+
page: z.number(),
|
|
37
|
+
per_page: z.number(),
|
|
38
|
+
previous_page: z.number().nullable(),
|
|
39
|
+
next_page: z.number().nullable(),
|
|
40
|
+
last_page: z.number(),
|
|
41
|
+
total_entries: z.number()
|
|
42
|
+
});
|
|
43
|
+
var HetznerMetaSchema = z.object({
|
|
44
|
+
pagination: HetznerPaginationSchema.optional()
|
|
45
|
+
});
|
|
46
|
+
var HetznerActionResourceSchema = z.object({
|
|
47
|
+
id: z.number(),
|
|
48
|
+
type: z.enum([
|
|
49
|
+
"server",
|
|
50
|
+
"volume",
|
|
51
|
+
"network",
|
|
52
|
+
"floating_ip",
|
|
53
|
+
"load_balancer",
|
|
54
|
+
"certificate",
|
|
55
|
+
"firewall",
|
|
56
|
+
"image"
|
|
57
|
+
])
|
|
58
|
+
});
|
|
59
|
+
var HetznerActionErrorSchema = z.object({
|
|
60
|
+
code: z.string(),
|
|
61
|
+
message: z.string()
|
|
62
|
+
});
|
|
63
|
+
var HetznerActionSchema = z.object({
|
|
64
|
+
id: z.number(),
|
|
65
|
+
command: z.string(),
|
|
66
|
+
status: z.nativeEnum(ActionStatus),
|
|
67
|
+
started: z.string(),
|
|
68
|
+
finished: z.string().nullable(),
|
|
69
|
+
progress: z.number().min(0).max(100),
|
|
70
|
+
resources: z.array(HetznerActionResourceSchema),
|
|
71
|
+
error: HetznerActionErrorSchema.nullable()
|
|
72
|
+
});
|
|
73
|
+
var HetznerActionResponseSchema = z.object({
|
|
74
|
+
action: HetznerActionSchema
|
|
75
|
+
});
|
|
76
|
+
var HetznerActionsResponseSchema = z.object({
|
|
77
|
+
actions: z.array(HetznerActionSchema),
|
|
78
|
+
meta: HetznerMetaSchema
|
|
79
|
+
});
|
|
80
|
+
var HetznerServerImageSchema = z.object({
|
|
81
|
+
id: z.number(),
|
|
82
|
+
name: z.string(),
|
|
83
|
+
description: z.string(),
|
|
84
|
+
type: z.enum(["snapshot", "backup", "system"])
|
|
85
|
+
});
|
|
86
|
+
var HetznerIPv4Schema = z.object({
|
|
87
|
+
ip: z.string().regex(ipv4Regex),
|
|
88
|
+
blocked: z.boolean()
|
|
89
|
+
});
|
|
90
|
+
var HetznerIPv6Schema = z.object({
|
|
91
|
+
ip: z.string().regex(ipv6Regex),
|
|
92
|
+
blocked: z.boolean()
|
|
93
|
+
});
|
|
94
|
+
var HetznerFloatingIpRefSchema = z.object({
|
|
95
|
+
id: z.number(),
|
|
96
|
+
ip: z.string()
|
|
97
|
+
});
|
|
98
|
+
var HetznerFirewallRefSchema = z.object({
|
|
99
|
+
id: z.number(),
|
|
100
|
+
name: z.string(),
|
|
101
|
+
status: z.enum(["applied", "pending"])
|
|
102
|
+
});
|
|
103
|
+
var HetznerPublicNetSchema = z.object({
|
|
104
|
+
ipv4: HetznerIPv4Schema,
|
|
105
|
+
ipv6: HetznerIPv6Schema.optional(),
|
|
106
|
+
floating_ips: z.array(HetznerFloatingIpRefSchema),
|
|
107
|
+
firewalls: z.array(HetznerFirewallRefSchema)
|
|
108
|
+
});
|
|
109
|
+
var HetznerServerTypeSchema = z.object({
|
|
110
|
+
id: z.number(),
|
|
111
|
+
name: z.string(),
|
|
112
|
+
description: z.string(),
|
|
113
|
+
cores: z.number(),
|
|
114
|
+
memory: z.number(),
|
|
115
|
+
disk: z.number()
|
|
116
|
+
});
|
|
117
|
+
var HetznerLocationSchema = z.object({
|
|
118
|
+
id: z.number(),
|
|
119
|
+
name: z.string(),
|
|
120
|
+
description: z.string(),
|
|
121
|
+
country: z.string(),
|
|
122
|
+
city: z.string(),
|
|
123
|
+
latitude: z.number(),
|
|
124
|
+
longitude: z.number(),
|
|
125
|
+
network_zone: z.string()
|
|
126
|
+
});
|
|
127
|
+
var HetznerDatacenterSchema = z.object({
|
|
128
|
+
id: z.number(),
|
|
129
|
+
name: z.string(),
|
|
130
|
+
description: z.string(),
|
|
131
|
+
location: HetznerLocationSchema,
|
|
132
|
+
supported_server_types: z.array(z.object({
|
|
133
|
+
id: z.number(),
|
|
134
|
+
name: z.string()
|
|
135
|
+
})).optional().nullable()
|
|
136
|
+
});
|
|
137
|
+
var HetznerVolumeRefSchema = z.object({
|
|
138
|
+
id: z.number(),
|
|
139
|
+
name: z.string(),
|
|
140
|
+
size: z.number().positive(),
|
|
141
|
+
linux_device: z.string()
|
|
142
|
+
});
|
|
143
|
+
var HetznerServerProtectionSchema = z.object({
|
|
144
|
+
delete: z.boolean(),
|
|
145
|
+
rebuild: z.boolean()
|
|
146
|
+
});
|
|
147
|
+
var HetznerServerSchema = z.object({
|
|
148
|
+
id: z.number().positive(),
|
|
149
|
+
name: z.string().min(1),
|
|
150
|
+
status: z.nativeEnum(EnvironmentStatus),
|
|
151
|
+
image: HetznerServerImageSchema.nullable().optional(),
|
|
152
|
+
public_net: HetznerPublicNetSchema,
|
|
153
|
+
server_type: HetznerServerTypeSchema,
|
|
154
|
+
datacenter: HetznerDatacenterSchema,
|
|
155
|
+
labels: z.record(z.string(), z.any()),
|
|
156
|
+
created: z.string().datetime(),
|
|
157
|
+
protection: HetznerServerProtectionSchema,
|
|
158
|
+
volumes: z.array(HetznerVolumeRefSchema)
|
|
159
|
+
});
|
|
160
|
+
var HetznerListServersResponseSchema = z.object({
|
|
161
|
+
servers: z.array(HetznerServerSchema),
|
|
162
|
+
meta: HetznerMetaSchema
|
|
163
|
+
});
|
|
164
|
+
var HetznerGetServerResponseSchema = z.object({
|
|
165
|
+
server: HetznerServerSchema
|
|
166
|
+
});
|
|
167
|
+
var HetznerCreateServerRequestSchema = z.object({
|
|
168
|
+
name: z.string().min(1).max(64).regex(/^[a-zA-Z0-9][a-zA-Z0-9-]*$/, "Name must start with letter/number and contain only letters, numbers, and hyphens"),
|
|
169
|
+
server_type: z.string().min(1),
|
|
170
|
+
image: z.string().min(1),
|
|
171
|
+
location: z.string().min(1).optional(),
|
|
172
|
+
datacenter: z.string().min(1).optional(),
|
|
173
|
+
ssh_keys: z.array(z.union([z.string(), z.number()])).optional(),
|
|
174
|
+
volumes: z.array(z.number().positive()).optional(),
|
|
175
|
+
labels: z.record(z.string(), z.any()).optional(),
|
|
176
|
+
start_after_create: z.boolean().optional()
|
|
177
|
+
}).refine((data) => !(data.location && data.datacenter), "Cannot specify both location and datacenter");
|
|
178
|
+
var HetznerCreateServerResponseSchema = z.object({
|
|
179
|
+
server: HetznerServerSchema,
|
|
180
|
+
action: HetznerActionSchema,
|
|
181
|
+
next_actions: z.array(HetznerActionSchema),
|
|
182
|
+
root_password: z.string().nullable()
|
|
183
|
+
});
|
|
184
|
+
var HetznerUpdateServerRequestSchema = z.object({
|
|
185
|
+
name: z.string().min(1).max(64).optional(),
|
|
186
|
+
labels: z.record(z.string(), z.any()).optional()
|
|
187
|
+
});
|
|
188
|
+
var HetznerUpdateServerResponseSchema = z.object({
|
|
189
|
+
server: HetznerServerSchema
|
|
190
|
+
});
|
|
191
|
+
var HetznerVolumeLocationSchema = z.object({
|
|
192
|
+
id: z.number(),
|
|
193
|
+
name: z.string(),
|
|
194
|
+
description: z.string(),
|
|
195
|
+
country: z.string(),
|
|
196
|
+
city: z.string(),
|
|
197
|
+
latitude: z.number(),
|
|
198
|
+
longitude: z.number()
|
|
199
|
+
});
|
|
200
|
+
var HetznerVolumeProtectionSchema = z.object({
|
|
201
|
+
delete: z.boolean()
|
|
202
|
+
});
|
|
203
|
+
var HetznerVolumeSchema = z.object({
|
|
204
|
+
id: z.number().positive(),
|
|
205
|
+
name: z.string().min(1),
|
|
206
|
+
status: z.nativeEnum(VolumeStatus),
|
|
207
|
+
server: z.number().positive().nullable().optional(),
|
|
208
|
+
size: z.number().positive(),
|
|
209
|
+
linux_device: z.string().nullable().optional(),
|
|
210
|
+
format: z.string().nullable().optional(),
|
|
211
|
+
location: HetznerVolumeLocationSchema.nullable().optional(),
|
|
212
|
+
labels: z.record(z.string(), z.any()),
|
|
213
|
+
created: z.string().datetime(),
|
|
214
|
+
protection: HetznerVolumeProtectionSchema
|
|
215
|
+
});
|
|
216
|
+
var HetznerListVolumesResponseSchema = z.object({
|
|
217
|
+
volumes: z.array(HetznerVolumeSchema),
|
|
218
|
+
meta: HetznerMetaSchema
|
|
219
|
+
});
|
|
220
|
+
var HetznerGetVolumeResponseSchema = z.object({
|
|
221
|
+
volume: HetznerVolumeSchema
|
|
222
|
+
});
|
|
223
|
+
var HetznerCreateVolumeRequestSchema = z.object({
|
|
224
|
+
name: z.string().min(1).max(64),
|
|
225
|
+
size: z.number().positive().multipleOf(1),
|
|
226
|
+
server: z.number().positive().optional(),
|
|
227
|
+
location: z.string().min(1).optional(),
|
|
228
|
+
automount: z.boolean().optional(),
|
|
229
|
+
format: z.string().optional(),
|
|
230
|
+
labels: z.record(z.string(), z.any()).optional()
|
|
231
|
+
}).refine((data) => {
|
|
232
|
+
return Number.isInteger(data.size);
|
|
233
|
+
}, "Volume size must be a whole number in GB");
|
|
234
|
+
var HetznerCreateVolumeResponseSchema = z.object({
|
|
235
|
+
volume: HetznerVolumeSchema,
|
|
236
|
+
action: HetznerActionSchema,
|
|
237
|
+
next_actions: z.array(HetznerActionSchema)
|
|
238
|
+
});
|
|
239
|
+
var HetznerSubnetSchema = z.object({
|
|
240
|
+
type: z.enum(["server", "cloud", "vswitch"]),
|
|
241
|
+
ip_range: z.string().regex(ipRegex),
|
|
242
|
+
network_zone: z.string(),
|
|
243
|
+
gateway: z.string().regex(ipRegex)
|
|
244
|
+
});
|
|
245
|
+
var HetznerRouteSchema = z.object({
|
|
246
|
+
destination: z.string().regex(ipRegex),
|
|
247
|
+
gateway: z.string().regex(ipRegex)
|
|
248
|
+
});
|
|
249
|
+
var HetznerNetworkProtectionSchema = z.object({
|
|
250
|
+
delete: z.boolean()
|
|
251
|
+
});
|
|
252
|
+
var HetznerNetworkSchema = z.object({
|
|
253
|
+
id: z.number().positive(),
|
|
254
|
+
name: z.string().min(1).max(64),
|
|
255
|
+
ip_range: z.string().regex(ipRegex),
|
|
256
|
+
subnets: z.array(HetznerSubnetSchema),
|
|
257
|
+
routes: z.array(HetznerRouteSchema),
|
|
258
|
+
servers: z.array(z.number().positive()),
|
|
259
|
+
protection: HetznerNetworkProtectionSchema,
|
|
260
|
+
labels: z.record(z.string(), z.any()),
|
|
261
|
+
created: z.string().datetime()
|
|
262
|
+
});
|
|
263
|
+
var HetznerListNetworksResponseSchema = z.object({
|
|
264
|
+
networks: z.array(HetznerNetworkSchema),
|
|
265
|
+
meta: HetznerMetaSchema
|
|
266
|
+
});
|
|
267
|
+
var HetznerGetNetworkResponseSchema = z.object({
|
|
268
|
+
network: HetznerNetworkSchema
|
|
269
|
+
});
|
|
270
|
+
var HetznerSSHKeySchema = z.object({
|
|
271
|
+
id: z.number().positive(),
|
|
272
|
+
name: z.string().min(1).max(64),
|
|
273
|
+
fingerprint: z.string(),
|
|
274
|
+
public_key: z.string(),
|
|
275
|
+
labels: z.record(z.string(), z.any()),
|
|
276
|
+
created: z.string().datetime()
|
|
277
|
+
});
|
|
278
|
+
var HetznerListSSHKeysResponseSchema = z.object({
|
|
279
|
+
ssh_keys: z.array(HetznerSSHKeySchema),
|
|
280
|
+
meta: HetznerMetaSchema
|
|
281
|
+
});
|
|
282
|
+
var HetznerGetSSHKeyResponseSchema = z.object({
|
|
283
|
+
ssh_key: HetznerSSHKeySchema
|
|
284
|
+
});
|
|
285
|
+
var HetznerCreateSSHKeyRequestSchema = z.object({
|
|
286
|
+
name: z.string().min(1).max(64).regex(/^[a-zA-Z0-9][a-zA-Z0-9-]*$/, "Name must start with letter/number and contain only letters, numbers, and hyphens"),
|
|
287
|
+
public_key: z.string().min(1),
|
|
288
|
+
labels: z.record(z.string(), z.any()).optional()
|
|
289
|
+
});
|
|
290
|
+
var HetznerCreateSSHKeyResponseSchema = z.object({
|
|
291
|
+
ssh_key: HetznerSSHKeySchema
|
|
292
|
+
});
|
|
293
|
+
var HetznerFloatingIpSchema = z.object({
|
|
294
|
+
id: z.number().positive(),
|
|
295
|
+
name: z.string().min(1).max(64),
|
|
296
|
+
description: z.string().optional(),
|
|
297
|
+
type: z.enum(["ipv4", "ipv6"]),
|
|
298
|
+
ip: z.string().regex(ipRegex),
|
|
299
|
+
server: z.number().positive().nullable(),
|
|
300
|
+
dns_ptr: z.array(z.object({
|
|
301
|
+
ip: z.string(),
|
|
302
|
+
dns_ptr: z.string()
|
|
303
|
+
})),
|
|
304
|
+
home_location: HetznerLocationSchema,
|
|
305
|
+
blocked: z.boolean(),
|
|
306
|
+
protection: z.object({
|
|
307
|
+
delete: z.boolean()
|
|
308
|
+
}),
|
|
309
|
+
labels: z.record(z.string(), z.any()),
|
|
310
|
+
created: z.string().datetime()
|
|
311
|
+
});
|
|
312
|
+
var HetznerListFloatingIpsResponseSchema = z.object({
|
|
313
|
+
floating_ips: z.array(HetznerFloatingIpSchema),
|
|
314
|
+
meta: HetznerMetaSchema
|
|
315
|
+
});
|
|
316
|
+
var HetznerFirewallRuleSchema = z.object({
|
|
317
|
+
direction: z.enum(["in", "out"]),
|
|
318
|
+
source_ips: z.array(z.string().regex(ipRegex)).optional(),
|
|
319
|
+
destination_ips: z.array(z.string().regex(ipRegex)).optional(),
|
|
320
|
+
source_port: z.string().optional(),
|
|
321
|
+
destination_port: z.string().optional(),
|
|
322
|
+
protocol: z.enum(["tcp", "udp", "icmp", "esp", "gre"])
|
|
323
|
+
});
|
|
324
|
+
var HetznerFirewallResourceSchema = z.object({
|
|
325
|
+
type: z.enum(["server", "label_selector"]),
|
|
326
|
+
server: z.object({
|
|
327
|
+
id: z.number().positive()
|
|
328
|
+
}).optional(),
|
|
329
|
+
label_selector: z.object({
|
|
330
|
+
selector: z.string()
|
|
331
|
+
}).optional()
|
|
332
|
+
});
|
|
333
|
+
var HetznerFirewallSchema = z.object({
|
|
334
|
+
id: z.number().positive(),
|
|
335
|
+
name: z.string().min(1).max(64),
|
|
336
|
+
rules: z.array(HetznerFirewallRuleSchema),
|
|
337
|
+
apply_to: z.array(HetznerFirewallResourceSchema),
|
|
338
|
+
labels: z.record(z.string(), z.any()),
|
|
339
|
+
created: z.string().datetime()
|
|
340
|
+
});
|
|
341
|
+
var HetznerListFirewallsResponseSchema = z.object({
|
|
342
|
+
firewalls: z.array(HetznerFirewallSchema),
|
|
343
|
+
meta: HetznerMetaSchema
|
|
344
|
+
});
|
|
345
|
+
var HetznerIsoSchema = z.object({
|
|
346
|
+
id: z.number().positive(),
|
|
347
|
+
name: z.string(),
|
|
348
|
+
description: z.string(),
|
|
349
|
+
type: z.enum(["public", "private"]),
|
|
350
|
+
deprecated: z.date().nullable().optional(),
|
|
351
|
+
architecture: z.array(z.enum(["x86", "arm"])).optional()
|
|
352
|
+
});
|
|
353
|
+
var HetznerListIsosResponseSchema = z.object({
|
|
354
|
+
isos: z.array(HetznerIsoSchema),
|
|
355
|
+
meta: HetznerMetaSchema
|
|
356
|
+
});
|
|
357
|
+
var HetznerListLocationsResponseSchema = z.object({
|
|
358
|
+
locations: z.array(HetznerLocationSchema)
|
|
359
|
+
});
|
|
360
|
+
var HetznerListDatacentersResponseSchema = z.object({
|
|
361
|
+
datacenters: z.array(HetznerDatacenterSchema)
|
|
362
|
+
});
|
|
363
|
+
var HetznerServerTypePricingSchema = z.object({
|
|
364
|
+
location: z.string().nullable().optional(),
|
|
365
|
+
price_hourly: z.object({
|
|
366
|
+
net: z.string(),
|
|
367
|
+
gross: z.string()
|
|
368
|
+
}),
|
|
369
|
+
price_monthly: z.object({
|
|
370
|
+
net: z.string(),
|
|
371
|
+
gross: z.string()
|
|
372
|
+
})
|
|
373
|
+
});
|
|
374
|
+
var HetznerServerTypeExtendedSchema = HetznerServerTypeSchema.extend({
|
|
375
|
+
deprecated: z.boolean().optional(),
|
|
376
|
+
prices: z.array(HetznerServerTypePricingSchema),
|
|
377
|
+
storage_type: z.enum(["local", "network"]),
|
|
378
|
+
cpu_type: z.enum(["shared", "dedicated"])
|
|
379
|
+
});
|
|
380
|
+
var HetznerListServerTypesResponseSchema = z.object({
|
|
381
|
+
server_types: z.array(HetznerServerTypeExtendedSchema)
|
|
382
|
+
});
|
|
383
|
+
var HetznerCertificateSchema = z.object({
|
|
384
|
+
id: z.number().positive(),
|
|
385
|
+
name: z.string().min(1).max(64),
|
|
386
|
+
labels: z.record(z.string(), z.any()),
|
|
387
|
+
certificate: z.string(),
|
|
388
|
+
not_valid_before: z.string().datetime(),
|
|
389
|
+
not_valid_after: z.string().datetime(),
|
|
390
|
+
domain_names: z.array(z.string().url()),
|
|
391
|
+
fingerprint: z.string(),
|
|
392
|
+
created: z.string().datetime(),
|
|
393
|
+
status: z.enum(["pending", "issued", "failed", "revoked"]),
|
|
394
|
+
failed: z.boolean().optional(),
|
|
395
|
+
type: z.enum(["uploaded", "managed"]),
|
|
396
|
+
usage: z.array(z.enum(["dual_stack", "server", "load_balancer", "dns"])).optional()
|
|
397
|
+
});
|
|
398
|
+
var HetznerListCertificatesResponseSchema = z.object({
|
|
399
|
+
certificates: z.array(HetznerCertificateSchema),
|
|
400
|
+
meta: HetznerMetaSchema
|
|
401
|
+
});
|
|
402
|
+
function createPaginatedResponseSchema(itemSchema, itemName) {
|
|
403
|
+
return z.object({
|
|
404
|
+
[itemName]: z.array(itemSchema),
|
|
405
|
+
meta: HetznerMetaSchema
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
function createItemResponseSchema(itemSchema, itemName) {
|
|
409
|
+
return z.object({
|
|
410
|
+
[itemName]: itemSchema
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/pricing.ts
|
|
415
|
+
import { z as z2 } from "zod";
|
|
416
|
+
var DEFAULT_FALLBACK_PRICE_MONTHLY = 5;
|
|
417
|
+
var HOURS_PER_MONTH = 730;
|
|
418
|
+
var ServerTypePriceSchema = z2.object({
|
|
419
|
+
serverType: z2.string(),
|
|
420
|
+
priceMonthly: z2.number().nonnegative(),
|
|
421
|
+
priceHourly: z2.number().nonnegative(),
|
|
422
|
+
deprecated: z2.boolean().optional().default(false)
|
|
423
|
+
});
|
|
424
|
+
var EnvironmentCostSchema = z2.object({
|
|
425
|
+
environmentId: z2.string(),
|
|
426
|
+
environmentName: z2.string(),
|
|
427
|
+
serverType: z2.string(),
|
|
428
|
+
isRunning: z2.boolean(),
|
|
429
|
+
costMonthly: z2.number().nonnegative(),
|
|
430
|
+
costHourly: z2.number().nonnegative(),
|
|
431
|
+
priceInfo: ServerTypePriceSchema.optional()
|
|
432
|
+
});
|
|
433
|
+
var CostCalculationResultSchema = z2.object({
|
|
434
|
+
totalMonthly: z2.number().nonnegative(),
|
|
435
|
+
totalHourly: z2.number().nonnegative(),
|
|
436
|
+
runningEnvironmentCount: z2.number().nonnegative().int(),
|
|
437
|
+
stoppedEnvironmentCount: z2.number().nonnegative().int(),
|
|
438
|
+
unknownServerTypeCount: z2.number().nonnegative().int(),
|
|
439
|
+
breakdown: z2.array(EnvironmentCostSchema),
|
|
440
|
+
priceMap: z2.custom()
|
|
441
|
+
});
|
|
442
|
+
function parseHetznerPrice(priceString) {
|
|
443
|
+
const parsed = parseFloat(priceString);
|
|
444
|
+
if (isNaN(parsed)) {
|
|
445
|
+
console.warn(`Failed to parse Hetzner price string: ${priceString}`);
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
return parsed;
|
|
449
|
+
}
|
|
450
|
+
function extractServerTypePrice(serverType) {
|
|
451
|
+
if (!serverType.prices || serverType.prices.length === 0) {
|
|
452
|
+
console.warn(`Server type ${serverType.name} has no pricing information`);
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const priceEntry = serverType.prices[0];
|
|
456
|
+
const priceMonthly = parseHetznerPrice(priceEntry.price_monthly.gross);
|
|
457
|
+
const priceHourly = parseHetznerPrice(priceEntry.price_hourly.gross);
|
|
458
|
+
return {
|
|
459
|
+
serverType: serverType.name,
|
|
460
|
+
priceMonthly,
|
|
461
|
+
priceHourly,
|
|
462
|
+
deprecated: serverType.deprecated ?? false
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function buildPriceMap(serverTypes) {
|
|
466
|
+
const priceMap = new Map;
|
|
467
|
+
for (const serverType of serverTypes) {
|
|
468
|
+
const priceInfo = extractServerTypePrice(serverType);
|
|
469
|
+
if (priceInfo) {
|
|
470
|
+
priceMap.set(serverType.name, priceInfo);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return priceMap;
|
|
474
|
+
}
|
|
475
|
+
function getServerTypeMonthlyPrice(serverTypeName, priceMap, fallbackPrice = DEFAULT_FALLBACK_PRICE_MONTHLY) {
|
|
476
|
+
const priceInfo = priceMap.get(serverTypeName);
|
|
477
|
+
return priceInfo?.priceMonthly ?? fallbackPrice;
|
|
478
|
+
}
|
|
479
|
+
function calculateHourlyFromMonthly(monthlyPrice) {
|
|
480
|
+
return monthlyPrice / HOURS_PER_MONTH;
|
|
481
|
+
}
|
|
482
|
+
function calculateCosts(environments, serverTypes, options = {}) {
|
|
483
|
+
const { fallbackPrice = DEFAULT_FALLBACK_PRICE_MONTHLY, includeStopped = false } = options;
|
|
484
|
+
const priceMap = buildPriceMap(serverTypes);
|
|
485
|
+
const breakdown = [];
|
|
486
|
+
let totalMonthly = 0;
|
|
487
|
+
let runningCount = 0;
|
|
488
|
+
let stoppedCount = 0;
|
|
489
|
+
let unknownTypeCount = 0;
|
|
490
|
+
for (const env of environments) {
|
|
491
|
+
const isRunning = env.status === "running";
|
|
492
|
+
const priceInfo = priceMap.get(env.serverType);
|
|
493
|
+
const isUnknownType = !priceInfo;
|
|
494
|
+
if (isRunning) {
|
|
495
|
+
runningCount++;
|
|
496
|
+
} else {
|
|
497
|
+
stoppedCount++;
|
|
498
|
+
}
|
|
499
|
+
if (isRunning && isUnknownType) {
|
|
500
|
+
unknownTypeCount++;
|
|
501
|
+
}
|
|
502
|
+
const monthlyPrice = isRunning ? priceInfo?.priceMonthly ?? fallbackPrice : 0;
|
|
503
|
+
const hourlyPrice = isRunning ? priceInfo?.priceHourly ?? calculateHourlyFromMonthly(fallbackPrice) : 0;
|
|
504
|
+
if (isRunning) {
|
|
505
|
+
totalMonthly += monthlyPrice;
|
|
506
|
+
}
|
|
507
|
+
if (isRunning || includeStopped) {
|
|
508
|
+
breakdown.push({
|
|
509
|
+
environmentId: env.id,
|
|
510
|
+
environmentName: env.name,
|
|
511
|
+
serverType: env.serverType,
|
|
512
|
+
isRunning,
|
|
513
|
+
costMonthly: monthlyPrice,
|
|
514
|
+
costHourly: hourlyPrice,
|
|
515
|
+
priceInfo
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
const totalHourly = calculateHourlyFromMonthly(totalMonthly);
|
|
520
|
+
return {
|
|
521
|
+
totalMonthly,
|
|
522
|
+
totalHourly,
|
|
523
|
+
runningEnvironmentCount: runningCount,
|
|
524
|
+
stoppedEnvironmentCount: stoppedCount,
|
|
525
|
+
unknownServerTypeCount: unknownTypeCount,
|
|
526
|
+
breakdown,
|
|
527
|
+
priceMap
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
class PricingOperations {
|
|
532
|
+
client;
|
|
533
|
+
constructor(client) {
|
|
534
|
+
this.client = client;
|
|
535
|
+
}
|
|
536
|
+
async listServerTypes() {
|
|
537
|
+
const response = await this.client.request("/server_types");
|
|
538
|
+
const validated = HetznerListServerTypesResponseSchema.safeParse(response);
|
|
539
|
+
if (!validated.success) {
|
|
540
|
+
console.warn("Hetzner list server types validation warning:", validated.error.issues);
|
|
541
|
+
return response.server_types;
|
|
542
|
+
}
|
|
543
|
+
return validated.data.server_types;
|
|
544
|
+
}
|
|
545
|
+
async getServerType(name) {
|
|
546
|
+
const types = await this.listServerTypes();
|
|
547
|
+
return types.find((t) => t.name === name);
|
|
548
|
+
}
|
|
549
|
+
async listLocations() {
|
|
550
|
+
const response = await this.client.request("/locations");
|
|
551
|
+
const validated = HetznerListLocationsResponseSchema.safeParse(response);
|
|
552
|
+
if (!validated.success) {
|
|
553
|
+
console.warn("Hetzner list locations validation warning:", validated.error.issues);
|
|
554
|
+
return response.locations;
|
|
555
|
+
}
|
|
556
|
+
return validated.data.locations;
|
|
557
|
+
}
|
|
558
|
+
async getLocation(name) {
|
|
559
|
+
const locations = await this.listLocations();
|
|
560
|
+
return locations.find((l) => l.name === name);
|
|
561
|
+
}
|
|
562
|
+
async listDatacenters() {
|
|
563
|
+
const response = await this.client.request("/datacenters");
|
|
564
|
+
const validated = HetznerListDatacentersResponseSchema.safeParse(response);
|
|
565
|
+
if (!validated.success) {
|
|
566
|
+
console.warn("Hetzner list datacenters validation warning:", validated.error.issues);
|
|
567
|
+
return response.datacenters;
|
|
568
|
+
}
|
|
569
|
+
return validated.data.datacenters;
|
|
570
|
+
}
|
|
571
|
+
async calculateEnvironmentCosts(environments, options) {
|
|
572
|
+
const serverTypes = await this.listServerTypes();
|
|
573
|
+
return calculateCosts(environments, serverTypes, options);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
export {
|
|
577
|
+
parseHetznerPrice,
|
|
578
|
+
getServerTypeMonthlyPrice,
|
|
579
|
+
extractServerTypePrice,
|
|
580
|
+
calculateHourlyFromMonthly,
|
|
581
|
+
calculateCosts,
|
|
582
|
+
buildPriceMap,
|
|
583
|
+
ServerTypePriceSchema,
|
|
584
|
+
PricingOperations,
|
|
585
|
+
EnvironmentCostSchema,
|
|
586
|
+
CostCalculationResultSchema
|
|
587
|
+
};
|