tslocal 0.1.0

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.
@@ -0,0 +1,1009 @@
1
+ // Code generated by cmd/typegen; DO NOT EDIT.
2
+
3
+ import { z } from "zod";
4
+
5
+ const goSlice = <T extends z.ZodTypeAny>(item: T) =>
6
+ z.array(item).nullish().transform(v => v ?? []);
7
+
8
+ const goMap = <V extends z.ZodTypeAny>(val: V) =>
9
+ z.record(z.string(), val).nullish().transform(v => v ?? {});
10
+
11
+ const int64 = z.union([z.number().int(), z.bigint()]).transform(v => BigInt(v));
12
+
13
+ /**
14
+ * Location represents geographical location data about a
15
+ * Tailscale host. Location is optional and only set if
16
+ * explicitly declared by a node.
17
+ */
18
+ export const LocationSchema = z.object({
19
+ /** User friendly country name, with proper capitalization ("Canada") */
20
+ Country: z.string().nullish(),
21
+ /** ISO 3166-1 alpha-2 in upper case ("CA") */
22
+ CountryCode: z.string().nullish(),
23
+ /** User friendly city name, with proper capitalization ("Squamish") */
24
+ City: z.string().nullish(),
25
+ /**
26
+ * CityCode is a short code representing the city in upper case.
27
+ * CityCode is used to disambiguate a city from another location
28
+ * with the same city name. It uniquely identifies a particular
29
+ * geographical location, within the tailnet.
30
+ * IATA, ICAO or ISO 3166-2 codes are recommended ("YSE")
31
+ */
32
+ CityCode: z.string().nullish(),
33
+ /**
34
+ * Latitude, Longitude are optional geographical coordinates of the node, in degrees.
35
+ * No particular accuracy level is promised; the coordinates may simply be the center of the city or country.
36
+ */
37
+ Latitude: z.number().nullish(),
38
+ Longitude: z.number().nullish(),
39
+ /**
40
+ * Priority determines the order of use of an exit node when a
41
+ * location based preference matches more than one exit node,
42
+ * the node with the highest priority wins. Nodes of equal
43
+ * probability may be selected arbitrarily.
44
+ *
45
+ * A value of 0 means the exit node does not have a priority
46
+ * preference. A negative int is not allowed.
47
+ */
48
+ Priority: int64.nullish(),
49
+ });
50
+ export type Location = z.infer<typeof LocationSchema>;
51
+
52
+ /**
53
+ * PeerStatus describes a peer node and its current state.
54
+ * WARNING: The fields in PeerStatus are merged by the AddPeer method in the StatusBuilder.
55
+ * When adding a new field to PeerStatus, you must update AddPeer to handle merging
56
+ * the new field. The AddPeer function is responsible for combining multiple updates
57
+ * to the same peer, and any new field that is not merged properly may lead to
58
+ * inconsistencies or lost data in the peer status.
59
+ */
60
+ export const PeerStatusSchema = z.object({
61
+ ID: z.string().default(""),
62
+ PublicKey: z.string().default(""),
63
+ /** HostInfo's Hostname (not a DNS name or necessarily unique) */
64
+ HostName: z.string().default(""),
65
+ /**
66
+ * DNSName is the Peer's FQDN. It ends with a dot.
67
+ * It has the form "host.<MagicDNSSuffix>."
68
+ */
69
+ DNSName: z.string().default(""),
70
+ /** HostInfo.OS */
71
+ OS: z.string().default(""),
72
+ UserID: int64.default(0n),
73
+ /**
74
+ * AltSharerUserID is the user who shared this node
75
+ * if it's different than UserID. Otherwise it's zero.
76
+ */
77
+ AltSharerUserID: int64.nullish(),
78
+ /** TailscaleIPs are the IP addresses assigned to the node. */
79
+ TailscaleIPs: goSlice(z.string()),
80
+ /** AllowedIPs are IP addresses allowed to route to this node. */
81
+ AllowedIPs: goSlice(z.string()),
82
+ /**
83
+ * Tags are the list of ACL tags applied to this node.
84
+ * See tailscale.com/tailcfg#Node.Tags for more information.
85
+ */
86
+ Tags: goSlice(z.string()),
87
+ /**
88
+ * PrimaryRoutes are the routes this node is currently the primary
89
+ * subnet router for, as determined by the control plane. It does
90
+ * not include the IPs in TailscaleIPs.
91
+ */
92
+ PrimaryRoutes: goSlice(z.string()),
93
+ /** Endpoints: */
94
+ Addrs: goSlice(z.string()),
95
+ /** one of Addrs, or unique if roaming */
96
+ CurAddr: z.string().default(""),
97
+ /** DERP region */
98
+ Relay: z.string().default(""),
99
+ /** peer relay address (ip:port:vni) */
100
+ PeerRelay: z.string().default(""),
101
+ RxBytes: int64.default(0n),
102
+ TxBytes: int64.default(0n),
103
+ /** time registered with tailcontrol */
104
+ Created: z.string().default(""),
105
+ /** time last packet sent */
106
+ LastWrite: z.string().default(""),
107
+ /** last seen to tailcontrol; only present if offline */
108
+ LastSeen: z.string().default(""),
109
+ /** with local wireguard */
110
+ LastHandshake: z.string().default(""),
111
+ /** whether node is connected to the control plane */
112
+ Online: z.boolean().default(false),
113
+ /** true if this is the currently selected exit node. */
114
+ ExitNode: z.boolean().default(false),
115
+ /** true if this node can be an exit node (offered && approved) */
116
+ ExitNodeOption: z.boolean().default(false),
117
+ /**
118
+ * Active is whether the node was recently active. The
119
+ * definition is somewhat undefined but has historically and
120
+ * currently means that there was some packet sent to this
121
+ * peer in the past two minutes. That definition is subject to
122
+ * change.
123
+ */
124
+ Active: z.boolean().default(false),
125
+ /** PeerAPIURL are the URLs of the node's PeerAPI servers. */
126
+ PeerAPIURL: goSlice(z.string()),
127
+ /** TaildropTargetStatus represents the node's eligibility to have files shared to it. */
128
+ TaildropTarget: int64.default(0n),
129
+ /** Reason why this peer cannot receive files. Empty if CanReceiveFiles=true */
130
+ NoFileSharingReason: z.string().default(""),
131
+ /**
132
+ * Capabilities are capabilities that the node has.
133
+ * They're free-form strings, but should be in the form of URLs/URIs
134
+ * such as:
135
+ * "https://tailscale.com/cap/is-admin"
136
+ * "https://tailscale.com/cap/file-sharing"
137
+ * "funnel"
138
+ *
139
+ * Deprecated: use CapMap instead. See https://github.com/tailscale/tailscale/issues/11508
140
+ * Every value is Capabilities is also a key in CapMap, even if it
141
+ * has no values in that map.
142
+ */
143
+ Capabilities: goSlice(z.string()),
144
+ /** CapMap is a map of capabilities to their values. */
145
+ CapMap: goMap(goSlice(z.unknown())),
146
+ /** SSH_HostKeys are the node's SSH host keys, if known. */
147
+ sshHostKeys: goSlice(z.string()),
148
+ /**
149
+ * ShareeNode indicates this node exists in the netmap because
150
+ * it's owned by a shared-to user and that node might connect
151
+ * to us. These nodes should be hidden by "tailscale status"
152
+ * etc by default.
153
+ */
154
+ ShareeNode: z.boolean().nullish(),
155
+ /**
156
+ * InNetworkMap means that this peer was seen in our latest network map.
157
+ * In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
158
+ */
159
+ InNetworkMap: z.boolean().default(false),
160
+ /**
161
+ * InMagicSock means that this peer is being tracked by magicsock.
162
+ * In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
163
+ */
164
+ InMagicSock: z.boolean().default(false),
165
+ /**
166
+ * InEngine means that this peer is tracked by the wireguard engine.
167
+ * In theory, all of InNetworkMap and InMagicSock and InEngine should all be true.
168
+ */
169
+ InEngine: z.boolean().default(false),
170
+ /**
171
+ * Expired means that this peer's node key has expired, based on either
172
+ * information from control or optimisically set on the client if the
173
+ * expiration time has passed.
174
+ */
175
+ Expired: z.boolean().nullish(),
176
+ /**
177
+ * KeyExpiry, if present, is the time at which the node key expired or
178
+ * will expire.
179
+ */
180
+ KeyExpiry: z.string().nullish(),
181
+ Location: LocationSchema.nullish(),
182
+ });
183
+ export type PeerStatus = z.infer<typeof PeerStatusSchema>;
184
+
185
+ /** ExitNodeStatus describes the current exit node. */
186
+ export const ExitNodeStatusSchema = z.object({
187
+ /** ID is the exit node's ID. */
188
+ ID: z.string().default(""),
189
+ /** Online is whether the exit node is alive. */
190
+ Online: z.boolean().default(false),
191
+ /** TailscaleIPs are the exit node's IP addresses assigned to the node. */
192
+ TailscaleIPs: goSlice(z.string()),
193
+ });
194
+ export type ExitNodeStatus = z.infer<typeof ExitNodeStatusSchema>;
195
+
196
+ /** TailnetStatus is information about a Tailscale network ("tailnet"). */
197
+ export const TailnetStatusSchema = z.object({
198
+ /** Name is the name of the network that's currently in use. */
199
+ Name: z.string().default(""),
200
+ /**
201
+ * MagicDNSSuffix is the network's MagicDNS suffix for nodes
202
+ * in the network such as "userfoo.tailscale.net".
203
+ * There are no surrounding dots.
204
+ * MagicDNSSuffix should be populated regardless of whether a domain
205
+ * has MagicDNS enabled.
206
+ */
207
+ MagicDNSSuffix: z.string().default(""),
208
+ /**
209
+ * MagicDNSEnabled is whether or not the network has MagicDNS enabled.
210
+ * Note that the current device may still not support MagicDNS if
211
+ * `--accept-dns=false` was used.
212
+ */
213
+ MagicDNSEnabled: z.boolean().default(false),
214
+ });
215
+ export type TailnetStatus = z.infer<typeof TailnetStatusSchema>;
216
+
217
+ /**
218
+ * A UserProfile is display-friendly data for a [User].
219
+ * It includes the LoginName for display purposes but *not* the Provider.
220
+ * It also includes derived data from one of the user's logins.
221
+ */
222
+ export const UserProfileSchema = z.object({
223
+ ID: int64.default(0n),
224
+ /** "alice@smith.com"; for display purposes only (provider is not listed) */
225
+ LoginName: z.string().default(""),
226
+ /** "Alice Smith" */
227
+ DisplayName: z.string().default(""),
228
+ ProfilePicURL: z.string().nullish(),
229
+ });
230
+ export type UserProfile = z.infer<typeof UserProfileSchema>;
231
+
232
+ /**
233
+ * ClientVersion is information about the latest client version that's available
234
+ * for the client (and whether they're already running it).
235
+ *
236
+ * It does not include a URL to download the client, as that varies by platform.
237
+ */
238
+ export const ClientVersionSchema = z.object({
239
+ /** RunningLatest is true if the client is running the latest build. */
240
+ RunningLatest: z.boolean().nullish(),
241
+ /**
242
+ * LatestVersion is the latest version.Short ("1.34.2") version available
243
+ * for download for the client's platform and packaging type.
244
+ * It won't be populated if RunningLatest is true.
245
+ */
246
+ LatestVersion: z.string().nullish(),
247
+ /**
248
+ * UrgentSecurityUpdate is set when the client is missing an important
249
+ * security update. That update may be in LatestVersion or earlier.
250
+ * UrgentSecurityUpdate should not be set if RunningLatest is false.
251
+ */
252
+ UrgentSecurityUpdate: z.boolean().nullish(),
253
+ /**
254
+ * Notify is whether the client should do an OS-specific notification about
255
+ * a new version being available. This should not be populated if
256
+ * RunningLatest is true. The client should not notify multiple times for
257
+ * the same LatestVersion value.
258
+ */
259
+ Notify: z.boolean().nullish(),
260
+ /**
261
+ * NotifyURL is a URL to open in the browser when the user clicks on the
262
+ * notification, when Notify is true.
263
+ */
264
+ NotifyURL: z.string().nullish(),
265
+ /** NotifyText is the text to show in the notification, when Notify is true. */
266
+ NotifyText: z.string().nullish(),
267
+ });
268
+ export type ClientVersion = z.infer<typeof ClientVersionSchema>;
269
+
270
+ /** Status represents the entire state of the IPN network. */
271
+ export const StatusSchema = z.object({
272
+ /** Version is the daemon's long version (see version.Long). */
273
+ Version: z.string().default(""),
274
+ /**
275
+ * TUN is whether /dev/net/tun (or equivalent kernel interface) is being
276
+ * used. If false, it's running in userspace mode.
277
+ */
278
+ TUN: z.boolean().default(false),
279
+ /**
280
+ * BackendState is an ipn.State string value:
281
+ * "NoState", "NeedsLogin", "NeedsMachineAuth", "Stopped",
282
+ * "Starting", "Running".
283
+ */
284
+ BackendState: z.string().default(""),
285
+ /** HaveNodeKey is whether the current profile has a node key configured. */
286
+ HaveNodeKey: z.boolean().nullish(),
287
+ /** current URL provided by control to authorize client */
288
+ AuthURL: z.string().default(""),
289
+ /** Tailscale IP(s) assigned to this node */
290
+ TailscaleIPs: goSlice(z.string()),
291
+ Self: PeerStatusSchema.nullish(),
292
+ /**
293
+ * ExitNodeStatus describes the current exit node.
294
+ * If nil, an exit node is not in use.
295
+ */
296
+ ExitNodeStatus: ExitNodeStatusSchema.nullish(),
297
+ /**
298
+ * Health contains health check problems.
299
+ * Empty means everything is good. (or at least that no known
300
+ * problems are detected)
301
+ */
302
+ Health: goSlice(z.string()),
303
+ /**
304
+ * This field is the legacy name of CurrentTailnet.MagicDNSSuffix.
305
+ *
306
+ * Deprecated: use CurrentTailnet.MagicDNSSuffix instead.
307
+ */
308
+ MagicDNSSuffix: z.string().default(""),
309
+ /**
310
+ * CurrentTailnet is information about the tailnet that the node
311
+ * is currently connected to. When not connected, this field is nil.
312
+ */
313
+ CurrentTailnet: TailnetStatusSchema.nullish(),
314
+ /**
315
+ * CertDomains are the set of DNS names for which the control
316
+ * plane server will assist with provisioning TLS
317
+ * certificates. See SetDNSRequest for dns-01 ACME challenges
318
+ * for e.g. LetsEncrypt. These names are FQDNs without
319
+ * trailing periods, and without any "_acme-challenge." prefix.
320
+ */
321
+ CertDomains: goSlice(z.string()),
322
+ /** Peer is the state of each peer, keyed by each peer's current public key. */
323
+ Peer: goMap(PeerStatusSchema),
324
+ /**
325
+ * User contains profile information about UserIDs referenced by
326
+ * PeerStatus.UserID, PeerStatus.AltSharerUserID, etc.
327
+ */
328
+ User: goMap(UserProfileSchema),
329
+ /**
330
+ * ClientVersion, when non-nil, contains information about the latest
331
+ * version of the Tailscale client that's available. Depending on
332
+ * the platform and client settings, it may not be available.
333
+ */
334
+ ClientVersion: ClientVersionSchema.nullish(),
335
+ });
336
+ export type Status = z.infer<typeof StatusSchema>;
337
+
338
+ /** Service represents a service running on a node. */
339
+ export const ServiceSchema = z.object({
340
+ /**
341
+ * Proto is the type of service. It's usually the constant TCP
342
+ * or UDP ("tcp" or "udp"), but it can also be one of the
343
+ * following meta service values:
344
+ *
345
+ * * "peerapi4": peerapi is available on IPv4; Port is the
346
+ * port number that the peerapi is running on the
347
+ * node's Tailscale IPv4 address.
348
+ * * "peerapi6": peerapi is available on IPv6; Port is the
349
+ * port number that the peerapi is running on the
350
+ * node's Tailscale IPv6 address.
351
+ * * "peerapi-dns-proxy": the local peerapi service supports
352
+ * being a DNS proxy (when the node is an exit
353
+ * node). For this service, the Port number must only be 1.
354
+ */
355
+ Proto: z.string().default(""),
356
+ /**
357
+ * Port is the port number.
358
+ *
359
+ * For Proto "peerapi-dns", it must be 1.
360
+ */
361
+ Port: z.number().default(0),
362
+ /**
363
+ * Description is the textual description of the service,
364
+ * usually the process name that's running.
365
+ */
366
+ Description: z.string().nullish(),
367
+ });
368
+ export type Service = z.infer<typeof ServiceSchema>;
369
+
370
+ /** NetInfo contains information about the host's network state. */
371
+ export const NetInfoSchema = z.object({
372
+ /**
373
+ * MappingVariesByDestIP says whether the host's NAT mappings
374
+ * vary based on the destination IP.
375
+ */
376
+ MappingVariesByDestIP: z.boolean().nullish(),
377
+ /** WorkingIPv6 is whether the host has IPv6 internet connectivity. */
378
+ WorkingIPv6: z.boolean().nullish(),
379
+ /**
380
+ * OSHasIPv6 is whether the OS supports IPv6 at all, regardless of
381
+ * whether IPv6 internet connectivity is available.
382
+ */
383
+ OSHasIPv6: z.boolean().nullish(),
384
+ /** WorkingUDP is whether the host has UDP internet connectivity. */
385
+ WorkingUDP: z.boolean().nullish(),
386
+ /**
387
+ * WorkingICMPv4 is whether ICMPv4 works.
388
+ * Empty means not checked.
389
+ */
390
+ WorkingICMPv4: z.boolean().nullish(),
391
+ /**
392
+ * HavePortMap is whether we have an existing portmap open
393
+ * (UPnP, PMP, or PCP).
394
+ */
395
+ HavePortMap: z.boolean().nullish(),
396
+ /**
397
+ * UPnP is whether UPnP appears present on the LAN.
398
+ * Empty means not checked.
399
+ */
400
+ UPnP: z.boolean().nullish(),
401
+ /**
402
+ * PMP is whether NAT-PMP appears present on the LAN.
403
+ * Empty means not checked.
404
+ */
405
+ PMP: z.boolean().nullish(),
406
+ /**
407
+ * PCP is whether PCP appears present on the LAN.
408
+ * Empty means not checked.
409
+ */
410
+ PCP: z.boolean().nullish(),
411
+ /**
412
+ * PreferredDERP is this node's preferred (home) DERP region ID.
413
+ * This is where the node expects to be contacted to begin a
414
+ * peer-to-peer connection. The node might be be temporarily
415
+ * connected to multiple DERP servers (to speak to other nodes
416
+ * that are located elsewhere) but PreferredDERP is the region ID
417
+ * that the node subscribes to traffic at.
418
+ * Zero means disconnected or unknown.
419
+ */
420
+ PreferredDERP: int64.nullish(),
421
+ /** LinkType is the current link type, if known. */
422
+ LinkType: z.string().nullish(),
423
+ /**
424
+ * DERPLatency is the fastest recent time to reach various
425
+ * DERP STUN servers, in seconds. The map key is the
426
+ * "regionID-v4" or "-v6"; it was previously the DERP server's
427
+ * STUN host:port.
428
+ *
429
+ * This should only be updated rarely, or when there's a
430
+ * material change, as any change here also gets uploaded to
431
+ * the control plane.
432
+ */
433
+ DERPLatency: goMap(z.number()),
434
+ /**
435
+ * FirewallMode encodes both which firewall mode was selected and why.
436
+ * It is Linux-specific (at least as of 2023-08-19) and is meant to help
437
+ * debug iptables-vs-nftables issues. The string is of the form
438
+ * "{nft,ift}-REASON", like "nft-forced" or "ipt-default". Empty means
439
+ * either not Linux or a configuration in which the host firewall rules
440
+ * are not managed by tailscaled.
441
+ */
442
+ FirewallMode: z.string().nullish(),
443
+ });
444
+ export type NetInfo = z.infer<typeof NetInfoSchema>;
445
+
446
+ /**
447
+ * TPMInfo contains information about a TPM 2.0 device present on a node.
448
+ * All fields are read from TPM_CAP_TPM_PROPERTIES, see Part 2, section 6.13 of
449
+ * https://trustedcomputinggroup.org/resource/tpm-library-specification/.
450
+ */
451
+ export const TPMInfoSchema = z.object({
452
+ /**
453
+ * Manufacturer is a 4-letter code from section 4.1 of
454
+ * https://trustedcomputinggroup.org/resource/vendor-id-registry/,
455
+ * for example "MSFT" for Microsoft.
456
+ * Read from TPM_PT_MANUFACTURER.
457
+ */
458
+ Manufacturer: z.string().nullish(),
459
+ /**
460
+ * Vendor is a vendor ID string, up to 16 characters.
461
+ * Read from TPM_PT_VENDOR_STRING_*.
462
+ */
463
+ Vendor: z.string().nullish(),
464
+ /**
465
+ * Model is a vendor-defined TPM model.
466
+ * Read from TPM_PT_VENDOR_TPM_TYPE.
467
+ */
468
+ Model: int64.nullish(),
469
+ /**
470
+ * FirmwareVersion is the version number of the firmware.
471
+ * Read from TPM_PT_FIRMWARE_VERSION_*.
472
+ */
473
+ FirmwareVersion: int64.nullish(),
474
+ /**
475
+ * SpecRevision is the TPM 2.0 spec revision encoded as a single number. All
476
+ * revisions can be found at
477
+ * https://trustedcomputinggroup.org/resource/tpm-library-specification/.
478
+ * Before revision 184, TCG used the "01.83" format for revision 183.
479
+ */
480
+ SpecRevision: int64.nullish(),
481
+ /**
482
+ * FamilyIndicator is the TPM spec family, like "2.0".
483
+ * Read from TPM_PT_FAMILY_INDICATOR.
484
+ */
485
+ FamilyIndicator: z.string().nullish(),
486
+ });
487
+ export type TPMInfo = z.infer<typeof TPMInfoSchema>;
488
+
489
+ /**
490
+ * Hostinfo contains a summary of a Tailscale host.
491
+ *
492
+ * Because it contains pointers (slices), this type should not be used
493
+ * as a value type.
494
+ */
495
+ export const HostinfoSchema = z.object({
496
+ /** version of this code (in version.Long format) */
497
+ IPNVersion: z.string().nullish(),
498
+ /** logtail ID of frontend instance */
499
+ FrontendLogID: z.string().nullish(),
500
+ /** logtail ID of backend instance */
501
+ BackendLogID: z.string().nullish(),
502
+ /** operating system the client runs on (a version.OS value) */
503
+ OS: z.string().nullish(),
504
+ /**
505
+ * OSVersion is the version of the OS, if available.
506
+ *
507
+ * For Android, it's like "10", "11", "12", etc. For iOS and macOS it's like
508
+ * "15.6.1" or "12.4.0". For Windows it's like "10.0.19044.1889". For
509
+ * FreeBSD it's like "12.3-STABLE".
510
+ *
511
+ * For Linux, prior to Tailscale 1.32, we jammed a bunch of fields into this
512
+ * string on Linux, like "Debian 10.4; kernel=xxx; container; env=kn" and so
513
+ * on. As of Tailscale 1.32, this is simply the kernel version on Linux, like
514
+ * "5.10.0-17-amd64".
515
+ */
516
+ OSVersion: z.string().nullish(),
517
+ /** best-effort whether the client is running in a container */
518
+ Container: z.boolean().nullish(),
519
+ /** a hostinfo.EnvType in string form */
520
+ Env: z.string().nullish(),
521
+ /** "debian", "ubuntu", "nixos", ... */
522
+ Distro: z.string().nullish(),
523
+ /** "20.04", ... */
524
+ DistroVersion: z.string().nullish(),
525
+ /** "jammy", "bullseye", ... */
526
+ DistroCodeName: z.string().nullish(),
527
+ /** App is used to disambiguate Tailscale clients that run using tsnet. */
528
+ App: z.string().nullish(),
529
+ /** if a desktop was detected on Linux */
530
+ Desktop: z.boolean().nullish(),
531
+ /** Tailscale package to disambiguate ("choco", "appstore", etc; "" for unknown) */
532
+ Package: z.string().nullish(),
533
+ /** mobile phone model ("Pixel 3a", "iPhone12,3") */
534
+ DeviceModel: z.string().nullish(),
535
+ /** macOS/iOS APNs device token for notifications (and Android in the future) */
536
+ PushDeviceToken: z.string().nullish(),
537
+ /** name of the host the client runs on */
538
+ Hostname: z.string().nullish(),
539
+ /** indicates whether the host is blocking incoming connections */
540
+ ShieldsUp: z.boolean().nullish(),
541
+ /** indicates this node exists in netmap because it's owned by a shared-to user */
542
+ ShareeNode: z.boolean().nullish(),
543
+ /** indicates that the user has opted out of sending logs and support */
544
+ NoLogsNoSupport: z.boolean().nullish(),
545
+ /**
546
+ * WireIngress indicates that the node would like to be wired up server-side
547
+ * (DNS, etc) to be able to use Tailscale Funnel, even if it's not currently
548
+ * enabled. For example, the user might only use it for intermittent
549
+ * foreground CLI serve sessions, for which they'd like it to work right
550
+ * away, even if it's disabled most of the time. As an optimization, this is
551
+ * only sent if IngressEnabled is false, as IngressEnabled implies that this
552
+ * option is true.
553
+ */
554
+ WireIngress: z.boolean().nullish(),
555
+ /** if the node has any funnel endpoint enabled */
556
+ IngressEnabled: z.boolean().nullish(),
557
+ /** indicates that the node has opted-in to admin-console-drive remote updates */
558
+ AllowsUpdate: z.boolean().nullish(),
559
+ /** the current host's machine type (uname -m) */
560
+ Machine: z.string().nullish(),
561
+ /** GOARCH value (of the built binary) */
562
+ GoArch: z.string().nullish(),
563
+ /** GOARM, GOAMD64, etc (of the built binary) */
564
+ GoArchVar: z.string().nullish(),
565
+ /** Go version binary was built with */
566
+ GoVersion: z.string().nullish(),
567
+ /** set of IP ranges this client can route */
568
+ RoutableIPs: goSlice(z.string()),
569
+ /** set of ACL tags this node wants to claim */
570
+ RequestTags: goSlice(z.string()),
571
+ /** MAC address(es) to send Wake-on-LAN packets to wake this node (lowercase hex w/ colons) */
572
+ WoLMACs: goSlice(z.string()),
573
+ /** services advertised by this machine */
574
+ Services: goSlice(ServiceSchema),
575
+ NetInfo: NetInfoSchema.nullish(),
576
+ /** if advertised */
577
+ sshHostKeys: goSlice(z.string()),
578
+ Cloud: z.string().nullish(),
579
+ /** if the client is running in userspace (netstack) mode */
580
+ Userspace: z.boolean().nullish(),
581
+ /** if the client's subnet router is running in userspace (netstack) mode */
582
+ UserspaceRouter: z.boolean().nullish(),
583
+ /** if the client is running the app-connector service */
584
+ AppConnector: z.boolean().nullish(),
585
+ /** opaque hash of the most recent list of tailnet services, change in hash indicates config should be fetched via c2n */
586
+ ServicesHash: z.string().nullish(),
587
+ /** the client’s selected exit node, empty when unselected. */
588
+ ExitNodeID: z.string().nullish(),
589
+ /**
590
+ * Location represents geographical location data about a
591
+ * Tailscale host. Location is optional and only set if
592
+ * explicitly declared by a node.
593
+ */
594
+ Location: LocationSchema.nullish(),
595
+ /** TPM device metadata, if available */
596
+ TPM: TPMInfoSchema.nullish(),
597
+ /**
598
+ * StateEncrypted reports whether the node state is stored encrypted on
599
+ * disk. The actual mechanism is platform-specific:
600
+ * * Apple nodes use the Keychain
601
+ * * Linux and Windows nodes use the TPM
602
+ * * Android apps use EncryptedSharedPreferences
603
+ */
604
+ StateEncrypted: z.boolean().nullish(),
605
+ });
606
+ export type Hostinfo = z.infer<typeof HostinfoSchema>;
607
+
608
+ /** Resolver is the configuration for one DNS resolver. */
609
+ export const ResolverSchema = z.object({
610
+ /**
611
+ * Addr is the address of the DNS resolver, one of:
612
+ * - A plain IP address for a "classic" UDP+TCP DNS resolver.
613
+ * This is the common format as sent by the control plane.
614
+ * - An IP:port, for tests.
615
+ * - "https://resolver.com/path" for DNS over HTTPS; currently
616
+ * as of 2022-09-08 only used for certain well-known resolvers
617
+ * (see the publicdns package) for which the IP addresses to dial DoH are
618
+ * known ahead of time, so bootstrap DNS resolution is not required.
619
+ * - "http://node-address:port/path" for DNS over HTTP over WireGuard. This
620
+ * is implemented in the PeerAPI for exit nodes and app connectors.
621
+ * - [TODO] "tls://resolver.com" for DNS over TCP+TLS
622
+ */
623
+ Addr: z.string().nullish(),
624
+ /**
625
+ * BootstrapResolution is an optional suggested resolution for the
626
+ * DoT/DoH resolver, if the resolver URL does not reference an IP
627
+ * address directly.
628
+ * BootstrapResolution may be empty, in which case clients should
629
+ * look up the DoT/DoH server using their local "classic" DNS
630
+ * resolver.
631
+ *
632
+ * As of 2022-09-08, BootstrapResolution is not yet used.
633
+ */
634
+ BootstrapResolution: goSlice(z.string()),
635
+ /**
636
+ * UseWithExitNode designates that this resolver should continue to be used when an
637
+ * exit node is in use. Normally, DNS resolution is delegated to the exit node but
638
+ * there are situations where it is preferable to still use a Split DNS server and/or
639
+ * global DNS server instead of the exit node.
640
+ */
641
+ UseWithExitNode: z.boolean().nullish(),
642
+ });
643
+ export type Resolver = z.infer<typeof ResolverSchema>;
644
+
645
+ /** Node is a Tailscale device in a tailnet. */
646
+ export const NodeSchema = z.object({
647
+ ID: int64.default(0n),
648
+ StableID: z.string().default(""),
649
+ /**
650
+ * Name is the FQDN of the node.
651
+ * It is also the MagicDNS name for the node.
652
+ * It has a trailing dot.
653
+ * e.g. "host.tail-scale.ts.net."
654
+ */
655
+ Name: z.string().default(""),
656
+ /**
657
+ * User is the user who created the node. If ACL tags are in use for the
658
+ * node then it doesn't reflect the ACL identity that the node is running
659
+ * as.
660
+ */
661
+ User: int64.default(0n),
662
+ /** Sharer, if non-zero, is the user who shared this node, if different than User. */
663
+ Sharer: int64.nullish(),
664
+ Key: z.string().default(""),
665
+ /** the zero value if this node does not expire */
666
+ KeyExpiry: z.string().nullish(),
667
+ KeySignature: z.string().nullish(),
668
+ Machine: z.string().nullish(),
669
+ DiscoKey: z.string().nullish(),
670
+ /** Addresses are the IP addresses of this Node directly. */
671
+ Addresses: goSlice(z.string()),
672
+ /**
673
+ * AllowedIPs are the IP ranges to route to this node.
674
+ *
675
+ * As of CapabilityVersion 112, this may be nil (null or undefined) on the wire
676
+ * to mean the same as Addresses. Internally, it is always filled in with
677
+ * its possibly-implicit value.
678
+ */
679
+ AllowedIPs: goSlice(z.string()),
680
+ /** IP+port (public via STUN, and local LANs) */
681
+ Endpoints: goSlice(z.string()),
682
+ /**
683
+ * LegacyDERPString is this node's home LegacyDERPString region ID integer, but shoved into an
684
+ * IP:port string for legacy reasons. The IP address is always "127.3.3.40"
685
+ * (a loopback address (127) followed by the digits over the letters DERP on
686
+ * a QWERTY keyboard (3.3.40)). The "port number" is the home LegacyDERPString region ID
687
+ * integer.
688
+ *
689
+ * Deprecated: HomeDERP has replaced this, but old servers might still send
690
+ * this field. See tailscale/tailscale#14636. Do not use this field in code
691
+ * other than in the upgradeNode func, which canonicalizes it to HomeDERP
692
+ * if it arrives as a LegacyDERPString string on the wire.
693
+ */
694
+ DERP: z.string().nullish(),
695
+ /**
696
+ * HomeDERP is the modern version of the DERP string field, with just an
697
+ * integer. The client advertises support for this as of capver 111.
698
+ *
699
+ * HomeDERP may be zero if not (yet) known, but ideally always be non-zero
700
+ * for magicsock connectivity to function normally.
701
+ */
702
+ HomeDERP: int64.nullish(),
703
+ Hostinfo: HostinfoSchema.nullish(),
704
+ Created: z.string().nullish(),
705
+ /** if non-zero, the node's capability version; old servers might not send */
706
+ Cap: int64.nullish(),
707
+ /**
708
+ * Tags are the list of ACL tags applied to this node.
709
+ * Tags take the form of `tag:<value>` where value starts
710
+ * with a letter and only contains alphanumerics and dashes `-`.
711
+ * Some valid tag examples:
712
+ * `tag:prod`
713
+ * `tag:database`
714
+ * `tag:lab-1`
715
+ */
716
+ Tags: goSlice(z.string()),
717
+ /**
718
+ * PrimaryRoutes are the routes from AllowedIPs that this node
719
+ * is currently the primary subnet router for, as determined
720
+ * by the control plane. It does not include the self address
721
+ * values from Addresses that are in AllowedIPs.
722
+ */
723
+ PrimaryRoutes: goSlice(z.string()),
724
+ /**
725
+ * LastSeen is when the node was last online. It is not
726
+ * updated when Online is true. It is nil if the current
727
+ * node doesn't have permission to know, or the node
728
+ * has never been online.
729
+ */
730
+ LastSeen: z.string().nullish(),
731
+ /**
732
+ * Online is whether the node is currently connected to the
733
+ * coordination server. A value of nil means unknown, or the
734
+ * current node doesn't have permission to know.
735
+ */
736
+ Online: z.boolean().nullish(),
737
+ /** TODO(crawshaw): replace with MachineStatus */
738
+ MachineAuthorized: z.boolean().nullish(),
739
+ /**
740
+ * Capabilities are capabilities that the node has.
741
+ * They're free-form strings, but should be in the form of URLs/URIs
742
+ * such as:
743
+ * "https://tailscale.com/cap/is-admin"
744
+ * "https://tailscale.com/cap/file-sharing"
745
+ *
746
+ * Deprecated: use CapMap instead. See https://github.com/tailscale/tailscale/issues/11508
747
+ */
748
+ Capabilities: goSlice(z.string()),
749
+ /**
750
+ * CapMap is a map of capabilities to their optional argument/data values.
751
+ *
752
+ * It is valid for a capability to not have any argument/data values; such
753
+ * capabilities can be tested for using the HasCap method. These type of
754
+ * capabilities are used to indicate that a node has a capability, but there
755
+ * is no additional data associated with it. These were previously
756
+ * represented by the Capabilities field, but can now be represented by
757
+ * CapMap with an empty value.
758
+ *
759
+ * See NodeCapability for more information on keys.
760
+ *
761
+ * Metadata about nodes can be transmitted in 3 ways:
762
+ * 1. MapResponse.Node.CapMap describes attributes that affect behavior for
763
+ * this node, such as which features have been enabled through the admin
764
+ * panel and any associated configuration details.
765
+ * 2. MapResponse.PacketFilter(s) describes access (both IP and application
766
+ * based) that should be granted to peers.
767
+ * 3. MapResponse.Peers[].CapMap describes attributes regarding a peer node,
768
+ * such as which features the peer supports or if that peer is preferred
769
+ * for a particular task vs other peers that could also be chosen.
770
+ */
771
+ CapMap: goMap(goSlice(z.unknown())),
772
+ /**
773
+ * UnsignedPeerAPIOnly means that this node is not signed nor subject to TKA
774
+ * restrictions. However, in exchange for that privilege, it does not get
775
+ * network access. It can only access this node's peerapi, which may not let
776
+ * it do anything. It is the tailscaled client's job to double-check the
777
+ * MapResponse's PacketFilter to verify that its AllowedIPs will not be
778
+ * accepted by the packet filter.
779
+ */
780
+ UnsignedPeerAPIOnly: z.boolean().nullish(),
781
+ /** MagicDNS base name (for normal non-shared-in nodes), FQDN (without trailing dot, for shared-in nodes), or Hostname (if no MagicDNS) */
782
+ ComputedName: z.string().nullish(),
783
+ /** either "ComputedName" or "ComputedName (computedHostIfDifferent)", if computedHostIfDifferent is set */
784
+ ComputedNameWithHost: z.string().nullish(),
785
+ /** DataPlaneAuditLogID is the per-node logtail ID used for data plane audit logging. */
786
+ DataPlaneAuditLogID: z.string().nullish(),
787
+ /**
788
+ * Expired is whether this node's key has expired. Control may send
789
+ * this; clients are only allowed to set this from false to true. On
790
+ * the client, this is calculated client-side based on a timestamp sent
791
+ * from control, to avoid clock skew issues.
792
+ */
793
+ Expired: z.boolean().nullish(),
794
+ /**
795
+ * SelfNodeV4MasqAddrForThisPeer is the IPv4 that this peer knows the current node as.
796
+ * It may be empty if the peer knows the current node by its native
797
+ * IPv4 address.
798
+ * This field is only populated in a MapResponse for peers and not
799
+ * for the current node.
800
+ *
801
+ * If set, it should be used to masquerade traffic originating from the
802
+ * current node to this peer. The masquerade address is only relevant
803
+ * for this peer and not for other peers.
804
+ *
805
+ * This only applies to traffic originating from the current node to the
806
+ * peer or any of its subnets. Traffic originating from subnet routes will
807
+ * not be masqueraded (e.g. in case of --snat-subnet-routes).
808
+ */
809
+ SelfNodeV4MasqAddrForThisPeer: z.string().nullish(),
810
+ /**
811
+ * SelfNodeV6MasqAddrForThisPeer is the IPv6 that this peer knows the current node as.
812
+ * It may be empty if the peer knows the current node by its native
813
+ * IPv6 address.
814
+ * This field is only populated in a MapResponse for peers and not
815
+ * for the current node.
816
+ *
817
+ * If set, it should be used to masquerade traffic originating from the
818
+ * current node to this peer. The masquerade address is only relevant
819
+ * for this peer and not for other peers.
820
+ *
821
+ * This only applies to traffic originating from the current node to the
822
+ * peer or any of its subnets. Traffic originating from subnet routes will
823
+ * not be masqueraded (e.g. in case of --snat-subnet-routes).
824
+ */
825
+ SelfNodeV6MasqAddrForThisPeer: z.string().nullish(),
826
+ /**
827
+ * IsWireGuardOnly indicates that this is a non-Tailscale WireGuard peer, it
828
+ * is not expected to speak Disco or DERP, and it must have Endpoints in
829
+ * order to be reachable.
830
+ */
831
+ IsWireGuardOnly: z.boolean().nullish(),
832
+ /**
833
+ * IsJailed indicates that this node is jailed and should not be allowed
834
+ * initiate connections, however outbound connections to it should still be
835
+ * allowed.
836
+ */
837
+ IsJailed: z.boolean().nullish(),
838
+ /**
839
+ * ExitNodeDNSResolvers is the list of DNS servers that should be used when this
840
+ * node is marked IsWireGuardOnly and being used as an exit node.
841
+ */
842
+ ExitNodeDNSResolvers: goSlice(ResolverSchema),
843
+ });
844
+ export type Node = z.infer<typeof NodeSchema>;
845
+
846
+ /**
847
+ * TCPPortHandler describes what to do when handling a TCP
848
+ * connection.
849
+ */
850
+ export const TCPPortHandlerSchema = z.object({
851
+ /**
852
+ * HTTPS, if true, means that tailscaled should handle this connection as an
853
+ * HTTPS request as configured by ServeConfig.Web.
854
+ *
855
+ * It is mutually exclusive with TCPForward.
856
+ */
857
+ HTTPS: z.boolean().nullish(),
858
+ /**
859
+ * HTTP, if true, means that tailscaled should handle this connection as an
860
+ * HTTP request as configured by ServeConfig.Web.
861
+ *
862
+ * It is mutually exclusive with TCPForward.
863
+ */
864
+ HTTP: z.boolean().nullish(),
865
+ /**
866
+ * TCPForward is the IP:port to forward TCP connections to.
867
+ * Whether or not TLS is terminated by tailscaled depends on
868
+ * TerminateTLS.
869
+ *
870
+ * It is mutually exclusive with HTTPS.
871
+ */
872
+ TCPForward: z.string().nullish(),
873
+ /**
874
+ * TerminateTLS, if non-empty, means that tailscaled should terminate the
875
+ * TLS connections before forwarding them to TCPForward, permitting only the
876
+ * SNI name with this value. It is only used if TCPForward is non-empty.
877
+ * (the HTTPS mode uses ServeConfig.Web)
878
+ */
879
+ TerminateTLS: z.string().nullish(),
880
+ /**
881
+ * ProxyProtocol indicates whether to send a PROXY protocol header
882
+ * before forwarding the connection to TCPForward.
883
+ *
884
+ * This is only valid if TCPForward is non-empty.
885
+ */
886
+ ProxyProtocol: int64.nullish(),
887
+ });
888
+ export type TCPPortHandler = z.infer<typeof TCPPortHandlerSchema>;
889
+
890
+ /** HTTPHandler is either a path or a proxy to serve. */
891
+ export const HTTPHandlerSchema = z.object({
892
+ /** absolute path to directory or file to serve */
893
+ Path: z.string().nullish(),
894
+ /** http://localhost:3000/, localhost:3030, 3030 */
895
+ Proxy: z.string().nullish(),
896
+ /** plaintext to serve (primarily for testing) */
897
+ Text: z.string().nullish(),
898
+ /** peer capabilities to forward in grant header, e.g. example.com/cap/mon */
899
+ AcceptAppCaps: goSlice(z.string()),
900
+ /**
901
+ * Redirect, if not empty, is the target URL to redirect requests to.
902
+ * By default, we redirect with HTTP 302 (Found) status.
903
+ * If Redirect starts with '<httpcode>:', then we use that status instead.
904
+ *
905
+ * The target URL supports the following expansion variables:
906
+ * - ${HOST}: replaced with the request's Host header value
907
+ * - ${REQUEST_URI}: replaced with the request's full URI (path and query string)
908
+ */
909
+ Redirect: z.string().nullish(),
910
+ });
911
+ export type HTTPHandler = z.infer<typeof HTTPHandlerSchema>;
912
+
913
+ /** WebServerConfig describes a web server's configuration. */
914
+ export const WebServerConfigSchema = z.object({
915
+ /** mountPoint => handler */
916
+ Handlers: goMap(HTTPHandlerSchema),
917
+ });
918
+ export type WebServerConfig = z.infer<typeof WebServerConfigSchema>;
919
+
920
+ /**
921
+ * ServiceConfig contains the config information for a single service.
922
+ * it contains a bool to indicate if the service is in Tun mode (L3 forwarding).
923
+ * If the service is not in Tun mode, the service is configured by the L4 forwarding
924
+ * (TCP ports) and/or the L7 forwarding (http handlers) information.
925
+ */
926
+ export const ServiceConfigSchema = z.object({
927
+ /**
928
+ * TCP are the list of TCP port numbers that tailscaled should handle for
929
+ * the Tailscale IP addresses. (not subnet routers, etc)
930
+ */
931
+ TCP: goMap(TCPPortHandlerSchema),
932
+ /**
933
+ * Web maps from "$SNI_NAME:$PORT" to a set of HTTP handlers
934
+ * keyed by mount point ("/", "/foo", etc)
935
+ */
936
+ Web: goMap(WebServerConfigSchema),
937
+ /** Tun determines if the service should be using L3 forwarding (Tun mode). */
938
+ Tun: z.boolean().nullish(),
939
+ });
940
+ export type ServiceConfig = z.infer<typeof ServiceConfigSchema>;
941
+
942
+ const _ServeConfigRef: z.ZodTypeAny = z.lazy(() => ServeConfigSchema);
943
+ /**
944
+ * ServeConfig is the JSON type stored in the StateStore for
945
+ * StateKey "_serve/$PROFILE_ID" as returned by ServeConfigKey.
946
+ */
947
+ export const ServeConfigSchema = z.object({
948
+ /**
949
+ * TCP are the list of TCP port numbers that tailscaled should handle for
950
+ * the Tailscale IP addresses. (not subnet routers, etc)
951
+ */
952
+ TCP: goMap(TCPPortHandlerSchema),
953
+ /**
954
+ * Web maps from "$SNI_NAME:$PORT" to a set of HTTP handlers
955
+ * keyed by mount point ("/", "/foo", etc)
956
+ */
957
+ Web: goMap(WebServerConfigSchema),
958
+ /**
959
+ * Services maps from service name (in the form "svc:dns-label") to a ServiceConfig.
960
+ * Which describes the L3, L4, and L7 forwarding information for the service.
961
+ */
962
+ Services: goMap(ServiceConfigSchema),
963
+ /**
964
+ * AllowFunnel is the set of SNI:port values for which funnel
965
+ * traffic is allowed, from trusted ingress peers.
966
+ */
967
+ AllowFunnel: goMap(z.boolean()),
968
+ /**
969
+ * Foreground is a map of an IPN Bus session ID to an alternate foreground serve config that's valid for the
970
+ * life of that WatchIPNBus session ID. This allows the config to specify ephemeral configs that are used
971
+ * in the CLI's foreground mode to ensure ungraceful shutdowns of either the client or the LocalBackend does not
972
+ * expose ports that users are not aware of. In practice this contains any serve config set via 'tailscale
973
+ * serve' command run without the '--bg' flag. ServeConfig contained by Foreground is not expected itself to contain
974
+ * another Foreground block.
975
+ */
976
+ Foreground: goMap(_ServeConfigRef),
977
+ });
978
+ export type ServeConfig = z.infer<typeof ServeConfigSchema> & {
979
+ /**
980
+ * ETag is the checksum of the serve config that's populated
981
+ * by the LocalClient through the HTTP ETag header during a
982
+ * GetServeConfig request and is translated to an If-Match header
983
+ * during a SetServeConfig request.
984
+ */
985
+ ETag: string;
986
+ };
987
+
988
+ /**
989
+ * WhoIsResponse is the JSON type returned by tailscaled debug server's /whois?ip=$IP handler.
990
+ * In successful whois responses, Node and UserProfile are never nil.
991
+ */
992
+ export const WhoIsResponseSchema = z.object({
993
+ Node: NodeSchema.nullish(),
994
+ UserProfile: UserProfileSchema.nullish(),
995
+ /**
996
+ * CapMap is a map of capabilities to their values.
997
+ * See tailcfg.PeerCapMap and tailcfg.PeerCapability for details.
998
+ */
999
+ CapMap: goMap(goSlice(z.unknown())),
1000
+ });
1001
+ export type WhoIsResponse = z.infer<typeof WhoIsResponseSchema>;
1002
+
1003
+ /** Alias for TailnetStatus for backward compatibility. */
1004
+ export const CurrentTailnetSchema = z.object({
1005
+ Name: z.string(),
1006
+ MagicDNSSuffix: z.string(),
1007
+ MagicDNSEnabled: z.boolean(),
1008
+ });
1009
+ export type CurrentTailnet = z.infer<typeof CurrentTailnetSchema>;