mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
enabling support for wireguard and firewall (#2713)
* wip: enabling support for wireguard and firewall * wip * wip * wip * wip * wip * implement some things * fix warning * wip * alpha.23 * misc fixes * remove ufw since no longer required * remove debug info * add cli bindings * debugging * fixes * individualized acme and privacy settings for domains and bindings * sdk version bump * migration * misc fixes * refactor Host::update * debug info * refactor webserver * misc fixes * misc fixes * refactor port forwarding * recheck interfaces every 5 min if no dbus event * misc fixes and cleanup * misc fixes
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
SetHealth,
|
||||
BindParams,
|
||||
HostId,
|
||||
LanInfo,
|
||||
NetInfo,
|
||||
Host,
|
||||
ExportServiceInterfaceParams,
|
||||
ServiceInterface,
|
||||
@@ -117,7 +117,7 @@ export type Effects = {
|
||||
packageId?: PackageId
|
||||
hostId: HostId
|
||||
internalPort: number
|
||||
}): Promise<LanInfo>
|
||||
}): Promise<NetInfo>
|
||||
/** Removes all network bindings, called in the setupInputSpec */
|
||||
clearBindings(options: {
|
||||
except: { id: HostId; internalPort: number }[]
|
||||
@@ -129,12 +129,6 @@ export type Effects = {
|
||||
hostId: HostId
|
||||
callback?: () => void
|
||||
}): Promise<Host | null>
|
||||
/** Returns the primary url that a user has selected for a host, if it exists */
|
||||
getPrimaryUrl(options: {
|
||||
packageId?: PackageId
|
||||
hostId: HostId
|
||||
callback?: () => void
|
||||
}): Promise<UrlString | null>
|
||||
/** Returns the IP address of the container */
|
||||
getContainerIp(): Promise<string>
|
||||
// interface
|
||||
|
||||
@@ -94,8 +94,8 @@ export class InputSpec<Type extends Record<string, any>, Store = never> {
|
||||
},
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
_TYPE: Type = null as any as Type
|
||||
_PARTIAL: DeepPartial<Type> = null as any as DeepPartial<Type>
|
||||
public _TYPE: Type = null as any as Type
|
||||
public _PARTIAL: DeepPartial<Type> = null as any as DeepPartial<Type>
|
||||
async build(options: LazyBuildOptions<Store>) {
|
||||
const answer = {} as {
|
||||
[K in keyof Type]: ValueSpec
|
||||
|
||||
@@ -49,6 +49,9 @@ export class Value<Type, Store> {
|
||||
public build: LazyBuild<Store, ValueSpec>,
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
public _TYPE: Type = null as any as Type
|
||||
public _PARTIAL: DeepPartial<Type> = null as any as DeepPartial<Type>
|
||||
|
||||
static toggle(a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
|
||||
@@ -31,7 +31,7 @@ export type CurrentDependenciesResult<Manifest extends T.SDKManifest> = {
|
||||
[K in RequiredDependenciesOf<Manifest>]: DependencyRequirement
|
||||
} & {
|
||||
[K in OptionalDependenciesOf<Manifest>]?: DependencyRequirement
|
||||
} & Record<string, DependencyRequirement>
|
||||
}
|
||||
|
||||
export function setupDependencies<Manifest extends T.SDKManifest>(
|
||||
fn: (options: {
|
||||
@@ -48,14 +48,16 @@ export function setupDependencies<Manifest extends T.SDKManifest>(
|
||||
}
|
||||
const dependencyType = await fn(options)
|
||||
return await options.effects.setDependencies({
|
||||
dependencies: Object.entries(dependencyType).map(
|
||||
([id, { versionRange, ...x }, ,]) =>
|
||||
({
|
||||
// id,
|
||||
...x,
|
||||
versionRange: versionRange.toString(),
|
||||
}) as T.DependencyRequirement,
|
||||
),
|
||||
dependencies: Object.entries(dependencyType)
|
||||
.map(([k, v]) => [k, v as DependencyRequirement] as const)
|
||||
.map(
|
||||
([id, { versionRange, ...x }]) =>
|
||||
({
|
||||
id,
|
||||
...x,
|
||||
versionRange: versionRange.toString(),
|
||||
}) as T.DependencyRequirement,
|
||||
),
|
||||
})
|
||||
}
|
||||
return cell.updater
|
||||
|
||||
@@ -46,7 +46,6 @@ export class Origin<T extends Host> {
|
||||
const {
|
||||
name,
|
||||
description,
|
||||
hasPrimary,
|
||||
id,
|
||||
type,
|
||||
username,
|
||||
@@ -67,7 +66,6 @@ export class Origin<T extends Host> {
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
hasPrimary,
|
||||
addressInfo,
|
||||
type,
|
||||
masked,
|
||||
|
||||
@@ -20,7 +20,6 @@ export class ServiceInterfaceBuilder {
|
||||
name: string
|
||||
id: string
|
||||
description: string
|
||||
hasPrimary: boolean
|
||||
type: ServiceInterfaceType
|
||||
username: string | null
|
||||
path: string
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type HostAddress =
|
||||
| { kind: "onion"; address: string }
|
||||
| { kind: "domain"; address: string }
|
||||
export type AcmeProvider = string
|
||||
@@ -1,13 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AcmeSettings = {
|
||||
provider: string
|
||||
/**
|
||||
* email addresses for letsencrypt
|
||||
*/
|
||||
contact: Array<string>
|
||||
/**
|
||||
* domains to get letsencrypt certs for
|
||||
*/
|
||||
domains: string[]
|
||||
}
|
||||
export type AcmeSettings = { contact: Array<string> }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { BindOptions } from "./BindOptions"
|
||||
import type { LanInfo } from "./LanInfo"
|
||||
import type { NetInfo } from "./NetInfo"
|
||||
|
||||
export type BindInfo = { enabled: boolean; options: BindOptions; lan: LanInfo }
|
||||
export type BindInfo = { enabled: boolean; options: BindOptions; net: NetInfo }
|
||||
|
||||
4
sdk/base/lib/osBindings/DomainConfig.ts
Normal file
4
sdk/base/lib/osBindings/DomainConfig.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AcmeProvider } from "./AcmeProvider"
|
||||
|
||||
export type DomainConfig = { public: boolean; acme: AcmeProvider | null }
|
||||
@@ -7,7 +7,6 @@ export type ExportServiceInterfaceParams = {
|
||||
id: ServiceInterfaceId
|
||||
name: string
|
||||
description: string
|
||||
hasPrimary: boolean
|
||||
masked: boolean
|
||||
addressInfo: AddressInfo
|
||||
type: ServiceInterfaceType
|
||||
|
||||
3
sdk/base/lib/osBindings/ForgetInterfaceParams.ts
Normal file
3
sdk/base/lib/osBindings/ForgetInterfaceParams.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ForgetInterfaceParams = { interface: string }
|
||||
@@ -1,10 +0,0 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CallbackId } from "./CallbackId"
|
||||
import type { HostId } from "./HostId"
|
||||
import type { PackageId } from "./PackageId"
|
||||
|
||||
export type GetPrimaryUrlParams = {
|
||||
packageId?: PackageId
|
||||
hostId: HostId
|
||||
callback?: CallbackId
|
||||
}
|
||||
3
sdk/base/lib/osBindings/GitHash.ts
Normal file
3
sdk/base/lib/osBindings/GitHash.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type GitHash = string
|
||||
@@ -1,13 +1,14 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { BindInfo } from "./BindInfo"
|
||||
import type { HostAddress } from "./HostAddress"
|
||||
import type { DomainConfig } from "./DomainConfig"
|
||||
import type { HostKind } from "./HostKind"
|
||||
import type { HostnameInfo } from "./HostnameInfo"
|
||||
|
||||
export type Host = {
|
||||
kind: HostKind
|
||||
bindings: { [key: number]: BindInfo }
|
||||
addresses: Array<HostAddress>
|
||||
onions: string[]
|
||||
domains: { [key: string]: DomainConfig }
|
||||
/**
|
||||
* COMPUTED: NetService::update
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
|
||||
export type IpHostname =
|
||||
| { kind: "ipv4"; value: string; port: number | null; sslPort: number | null }
|
||||
| { kind: "ipv6"; value: string; port: number | null; sslPort: number | null }
|
||||
| {
|
||||
kind: "ipv6"
|
||||
value: string
|
||||
scopeId: number
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
| {
|
||||
kind: "local"
|
||||
value: string
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { NetworkInterfaceType } from "./NetworkInterfaceType"
|
||||
|
||||
export type IpInfo = {
|
||||
ipv4Range: string | null
|
||||
ipv4: string | null
|
||||
ipv6Range: string | null
|
||||
ipv6: string | null
|
||||
scopeId: number
|
||||
deviceType: NetworkInterfaceType | null
|
||||
subnets: string[]
|
||||
wanIp: string | null
|
||||
ntpServers: string[]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { Alerts } from "./Alerts"
|
||||
import type { Dependencies } from "./Dependencies"
|
||||
import type { Description } from "./Description"
|
||||
import type { GitHash } from "./GitHash"
|
||||
import type { HardwareRequirements } from "./HardwareRequirements"
|
||||
import type { ImageConfig } from "./ImageConfig"
|
||||
import type { ImageId } from "./ImageId"
|
||||
@@ -30,6 +31,6 @@ export type Manifest = {
|
||||
alerts: Alerts
|
||||
dependencies: Dependencies
|
||||
hardwareRequirements: HardwareRequirements
|
||||
gitHash: string | null
|
||||
gitHash?: GitHash
|
||||
osVersion: string
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type LanInfo = {
|
||||
export type NetInfo = {
|
||||
public: boolean
|
||||
assignedPort: number | null
|
||||
assignedSslPort: number | null
|
||||
}
|
||||
7
sdk/base/lib/osBindings/NetworkInterfaceInfo.ts
Normal file
7
sdk/base/lib/osBindings/NetworkInterfaceInfo.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { IpInfo } from "./IpInfo"
|
||||
|
||||
export type NetworkInterfaceInfo = {
|
||||
public: boolean | null
|
||||
ipInfo: IpInfo | null
|
||||
}
|
||||
3
sdk/base/lib/osBindings/NetworkInterfaceType.ts
Normal file
3
sdk/base/lib/osBindings/NetworkInterfaceType.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type NetworkInterfaceType = "ethernet" | "wireless" | "wireguard"
|
||||
@@ -3,6 +3,7 @@ import type { Alerts } from "./Alerts"
|
||||
import type { DataUrl } from "./DataUrl"
|
||||
import type { DependencyMetadata } from "./DependencyMetadata"
|
||||
import type { Description } from "./Description"
|
||||
import type { GitHash } from "./GitHash"
|
||||
import type { HardwareRequirements } from "./HardwareRequirements"
|
||||
import type { MerkleArchiveCommitment } from "./MerkleArchiveCommitment"
|
||||
import type { PackageId } from "./PackageId"
|
||||
@@ -13,7 +14,7 @@ export type PackageVersionInfo = {
|
||||
icon: DataUrl
|
||||
description: Description
|
||||
releaseNotes: string
|
||||
gitHash: string
|
||||
gitHash: GitHash
|
||||
license: string
|
||||
wrapperRepo: string
|
||||
upstreamRepo: string
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AcmeProvider } from "./AcmeProvider"
|
||||
import type { AcmeSettings } from "./AcmeSettings"
|
||||
import type { Governor } from "./Governor"
|
||||
import type { IpInfo } from "./IpInfo"
|
||||
import type { LshwDevice } from "./LshwDevice"
|
||||
import type { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
|
||||
import type { ServerStatus } from "./ServerStatus"
|
||||
import type { SmtpValue } from "./SmtpValue"
|
||||
import type { WifiInfo } from "./WifiInfo"
|
||||
@@ -22,8 +23,8 @@ export type ServerInfo = {
|
||||
* for backwards compatibility
|
||||
*/
|
||||
torAddress: string
|
||||
ipInfo: { [key: string]: IpInfo }
|
||||
acme: AcmeSettings | null
|
||||
networkInterfaces: { [key: string]: NetworkInterfaceInfo }
|
||||
acme: { [key: AcmeProvider]: AcmeSettings }
|
||||
statusInfo: ServerStatus
|
||||
wifi: WifiInfo
|
||||
unreadNotificationCount: number
|
||||
|
||||
@@ -7,7 +7,6 @@ export type ServiceInterface = {
|
||||
id: ServiceInterfaceId
|
||||
name: string
|
||||
description: string
|
||||
hasPrimary: boolean
|
||||
masked: boolean
|
||||
addressInfo: AddressInfo
|
||||
type: ServiceInterfaceType
|
||||
|
||||
3
sdk/base/lib/osBindings/SetPublicParams.ts
Normal file
3
sdk/base/lib/osBindings/SetPublicParams.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SetPublicParams = { interface: string; public: boolean | null }
|
||||
3
sdk/base/lib/osBindings/UnsetPublicParams.ts
Normal file
3
sdk/base/lib/osBindings/UnsetPublicParams.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type UnsetPublicParams = { interface: string }
|
||||
@@ -1,4 +1,5 @@
|
||||
export { AcceptSigners } from "./AcceptSigners"
|
||||
export { AcmeProvider } from "./AcmeProvider"
|
||||
export { AcmeSettings } from "./AcmeSettings"
|
||||
export { ActionId } from "./ActionId"
|
||||
export { ActionInput } from "./ActionInput"
|
||||
@@ -66,6 +67,7 @@ export { DepInfo } from "./DepInfo"
|
||||
export { Description } from "./Description"
|
||||
export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams"
|
||||
export { DeviceFilter } from "./DeviceFilter"
|
||||
export { DomainConfig } from "./DomainConfig"
|
||||
export { Duration } from "./Duration"
|
||||
export { EchoParams } from "./EchoParams"
|
||||
export { EditSignerParams } from "./EditSignerParams"
|
||||
@@ -73,6 +75,7 @@ export { EncryptedWire } from "./EncryptedWire"
|
||||
export { ExportActionParams } from "./ExportActionParams"
|
||||
export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams"
|
||||
export { ExposeForDependentsParams } from "./ExposeForDependentsParams"
|
||||
export { ForgetInterfaceParams } from "./ForgetInterfaceParams"
|
||||
export { FullIndex } from "./FullIndex"
|
||||
export { FullProgress } from "./FullProgress"
|
||||
export { GetActionInputParams } from "./GetActionInputParams"
|
||||
@@ -82,7 +85,6 @@ export { GetOsVersionParams } from "./GetOsVersionParams"
|
||||
export { GetPackageParams } from "./GetPackageParams"
|
||||
export { GetPackageResponseFull } from "./GetPackageResponseFull"
|
||||
export { GetPackageResponse } from "./GetPackageResponse"
|
||||
export { GetPrimaryUrlParams } from "./GetPrimaryUrlParams"
|
||||
export { GetServiceInterfaceParams } from "./GetServiceInterfaceParams"
|
||||
export { GetServicePortForwardParams } from "./GetServicePortForwardParams"
|
||||
export { GetSslCertificateParams } from "./GetSslCertificateParams"
|
||||
@@ -90,11 +92,11 @@ export { GetSslKeyParams } from "./GetSslKeyParams"
|
||||
export { GetStatusParams } from "./GetStatusParams"
|
||||
export { GetStoreParams } from "./GetStoreParams"
|
||||
export { GetSystemSmtpParams } from "./GetSystemSmtpParams"
|
||||
export { GitHash } from "./GitHash"
|
||||
export { Governor } from "./Governor"
|
||||
export { Guid } from "./Guid"
|
||||
export { HardwareRequirements } from "./HardwareRequirements"
|
||||
export { HealthCheckId } from "./HealthCheckId"
|
||||
export { HostAddress } from "./HostAddress"
|
||||
export { HostId } from "./HostId"
|
||||
export { HostKind } from "./HostKind"
|
||||
export { HostnameInfo } from "./HostnameInfo"
|
||||
@@ -112,7 +114,6 @@ export { InstallingState } from "./InstallingState"
|
||||
export { InstallParams } from "./InstallParams"
|
||||
export { IpHostname } from "./IpHostname"
|
||||
export { IpInfo } from "./IpInfo"
|
||||
export { LanInfo } from "./LanInfo"
|
||||
export { ListPackageSignersParams } from "./ListPackageSignersParams"
|
||||
export { ListServiceInterfacesParams } from "./ListServiceInterfacesParams"
|
||||
export { ListVersionSignersParams } from "./ListVersionSignersParams"
|
||||
@@ -128,6 +129,9 @@ export { MountParams } from "./MountParams"
|
||||
export { MountTarget } from "./MountTarget"
|
||||
export { NamedHealthCheckResult } from "./NamedHealthCheckResult"
|
||||
export { NamedProgress } from "./NamedProgress"
|
||||
export { NetInfo } from "./NetInfo"
|
||||
export { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
|
||||
export { NetworkInterfaceType } from "./NetworkInterfaceType"
|
||||
export { OnionHostname } from "./OnionHostname"
|
||||
export { OsIndex } from "./OsIndex"
|
||||
export { OsVersionInfoMap } from "./OsVersionInfoMap"
|
||||
@@ -172,6 +176,7 @@ export { SetIconParams } from "./SetIconParams"
|
||||
export { SetMainStatusStatus } from "./SetMainStatusStatus"
|
||||
export { SetMainStatus } from "./SetMainStatus"
|
||||
export { SetNameParams } from "./SetNameParams"
|
||||
export { SetPublicParams } from "./SetPublicParams"
|
||||
export { SetStoreParams } from "./SetStoreParams"
|
||||
export { SetupExecuteParams } from "./SetupExecuteParams"
|
||||
export { SetupProgress } from "./SetupProgress"
|
||||
@@ -181,6 +186,7 @@ export { SignAssetParams } from "./SignAssetParams"
|
||||
export { SignerInfo } from "./SignerInfo"
|
||||
export { SmtpValue } from "./SmtpValue"
|
||||
export { StartStop } from "./StartStop"
|
||||
export { UnsetPublicParams } from "./UnsetPublicParams"
|
||||
export { UpdatingState } from "./UpdatingState"
|
||||
export { VerifyCifsParams } from "./VerifyCifsParams"
|
||||
export { VersionSignerParams } from "./VersionSignerParams"
|
||||
|
||||
@@ -26,7 +26,6 @@ import { SetDependenciesParams } from ".././osBindings"
|
||||
import { GetSystemSmtpParams } from ".././osBindings"
|
||||
import { GetServicePortForwardParams } from ".././osBindings"
|
||||
import { ExportServiceInterfaceParams } from ".././osBindings"
|
||||
import { GetPrimaryUrlParams } from ".././osBindings"
|
||||
import { ListServiceInterfacesParams } from ".././osBindings"
|
||||
import { ExportActionParams } from ".././osBindings"
|
||||
import { MountParams } from ".././osBindings"
|
||||
@@ -83,7 +82,6 @@ describe("startosTypeValidation ", () => {
|
||||
getServicePortForward: {} as GetServicePortForwardParams,
|
||||
clearServiceInterfaces: {} as ClearServiceInterfacesParams,
|
||||
exportServiceInterface: {} as ExportServiceInterfaceParams,
|
||||
getPrimaryUrl: {} as WithCallback<GetPrimaryUrlParams>,
|
||||
listServiceInterfaces: {} as WithCallback<ListServiceInterfacesParams>,
|
||||
mount: {} as MountParams,
|
||||
checkDependencies: {} as CheckDependenciesParam,
|
||||
|
||||
@@ -138,33 +138,6 @@ export declare const hostName: unique symbol
|
||||
// asdflkjadsf.onion | 1.2.3.4
|
||||
export type Hostname = string & { [hostName]: never }
|
||||
|
||||
export type HostnameInfoIp = {
|
||||
kind: "ip"
|
||||
networkInterfaceId: string
|
||||
public: boolean
|
||||
hostname:
|
||||
| {
|
||||
kind: "ipv4" | "ipv6" | "local"
|
||||
value: string
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
| {
|
||||
kind: "domain"
|
||||
domain: string
|
||||
subdomain: string | null
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export type HostnameInfoOnion = {
|
||||
kind: "onion"
|
||||
hostname: { value: string; port: number | null; sslPort: number | null }
|
||||
}
|
||||
|
||||
export type HostnameInfo = HostnameInfoIp | HostnameInfoOnion
|
||||
|
||||
export type ServiceInterfaceId = string
|
||||
|
||||
export { ServiceInterface }
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import { ServiceInterfaceType } from "../types"
|
||||
import { knownProtocols } from "../interfaces/Host"
|
||||
import {
|
||||
AddressInfo,
|
||||
Host,
|
||||
HostAddress,
|
||||
Hostname,
|
||||
HostnameInfo,
|
||||
HostnameInfoIp,
|
||||
HostnameInfoOnion,
|
||||
IpInfo,
|
||||
} from "../types"
|
||||
import { AddressInfo, Host, Hostname, HostnameInfo } from "../types"
|
||||
import { Effects } from "../Effects"
|
||||
|
||||
export type UrlString = string
|
||||
@@ -48,8 +39,6 @@ export type ServiceInterfaceFilled = {
|
||||
name: string
|
||||
/** Human readable description, used as tooltip usually */
|
||||
description: string
|
||||
/** Whether or not the interface has a primary URL */
|
||||
hasPrimary: boolean
|
||||
/** Whether or not to mask the URIs for this interface. Useful if the URIs contain sensitive information, such as a password, macaroon, or API key */
|
||||
masked: boolean
|
||||
/** Information about the host for this binding */
|
||||
@@ -58,10 +47,6 @@ export type ServiceInterfaceFilled = {
|
||||
addressInfo: FilledAddressInfo | null
|
||||
/** Indicates if we are a ui/p2p/api for the kind of interface that this is representing */
|
||||
type: ServiceInterfaceType
|
||||
/** The primary hostname for the service, as chosen by the user */
|
||||
primaryHostname: Hostname | null
|
||||
/** The primary URL for the service, as chosen by the user */
|
||||
primaryUrl: UrlString | null
|
||||
}
|
||||
const either =
|
||||
<A>(...args: ((a: A) => boolean)[]) =>
|
||||
@@ -89,7 +74,9 @@ export const addressHostToUrl = (
|
||||
if (host.hostname.kind === "domain") {
|
||||
hostname = `${host.hostname.subdomain ? `${host.hostname.subdomain}.` : ""}${host.hostname.domain}`
|
||||
} else if (host.hostname.kind === "ipv6") {
|
||||
hostname = `[${host.hostname.value}]`
|
||||
hostname = host.hostname.value.startsWith("fe80::")
|
||||
? `[${host.hostname.value}%${host.hostname.scopeId}]`
|
||||
: `[${host.hostname.value}]`
|
||||
} else {
|
||||
hostname = host.hostname.value
|
||||
}
|
||||
@@ -200,23 +187,13 @@ const makeInterfaceFilled = async ({
|
||||
hostId,
|
||||
callback,
|
||||
})
|
||||
const primaryUrl = await effects.getPrimaryUrl({
|
||||
hostId,
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
|
||||
const interfaceFilled: ServiceInterfaceFilled = {
|
||||
...serviceInterfaceValue,
|
||||
primaryUrl: primaryUrl,
|
||||
host,
|
||||
addressInfo: host
|
||||
? filledAddress(host, serviceInterfaceValue.addressInfo)
|
||||
: null,
|
||||
get primaryHostname() {
|
||||
if (primaryUrl == null) return null
|
||||
return getHostname(primaryUrl)
|
||||
},
|
||||
}
|
||||
return interfaceFilled
|
||||
}
|
||||
|
||||
@@ -30,22 +30,10 @@ const makeManyInterfaceFilled = async ({
|
||||
if (!host) {
|
||||
throw new Error(`host ${hostId} not found!`)
|
||||
}
|
||||
const primaryUrl = await effects
|
||||
.getPrimaryUrl({
|
||||
hostId,
|
||||
packageId,
|
||||
callback,
|
||||
})
|
||||
.catch(() => null)
|
||||
return {
|
||||
...serviceInterfaceValue,
|
||||
primaryUrl: primaryUrl,
|
||||
host,
|
||||
addressInfo: filledAddress(host, serviceInterfaceValue.addressInfo),
|
||||
get primaryHostname() {
|
||||
if (primaryUrl == null) return null
|
||||
return getHostname(primaryUrl)
|
||||
},
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -2,58 +2,58 @@ import { Pattern } from "../actions/input/inputSpecTypes"
|
||||
import * as regexes from "./regexes"
|
||||
|
||||
export const ipv6: Pattern = {
|
||||
regex: regexes.ipv6.toString(),
|
||||
regex: regexes.ipv6.source,
|
||||
description: "Must be a valid IPv6 address",
|
||||
}
|
||||
|
||||
export const ipv4: Pattern = {
|
||||
regex: regexes.ipv4.toString(),
|
||||
regex: regexes.ipv4.source,
|
||||
description: "Must be a valid IPv4 address",
|
||||
}
|
||||
|
||||
export const hostname: Pattern = {
|
||||
regex: regexes.hostname.toString(),
|
||||
regex: regexes.hostname.source,
|
||||
description: "Must be a valid hostname",
|
||||
}
|
||||
|
||||
export const localHostname: Pattern = {
|
||||
regex: regexes.localHostname.toString(),
|
||||
regex: regexes.localHostname.source,
|
||||
description: 'Must be a valid ".local" hostname',
|
||||
}
|
||||
|
||||
export const torHostname: Pattern = {
|
||||
regex: regexes.torHostname.toString(),
|
||||
regex: regexes.torHostname.source,
|
||||
description: 'Must be a valid Tor (".onion") hostname',
|
||||
}
|
||||
|
||||
export const url: Pattern = {
|
||||
regex: regexes.url.toString(),
|
||||
regex: regexes.url.source,
|
||||
description: "Must be a valid URL",
|
||||
}
|
||||
|
||||
export const localUrl: Pattern = {
|
||||
regex: regexes.localUrl.toString(),
|
||||
regex: regexes.localUrl.source,
|
||||
description: 'Must be a valid ".local" URL',
|
||||
}
|
||||
|
||||
export const torUrl: Pattern = {
|
||||
regex: regexes.torUrl.toString(),
|
||||
regex: regexes.torUrl.source,
|
||||
description: 'Must be a valid Tor (".onion") URL',
|
||||
}
|
||||
|
||||
export const ascii: Pattern = {
|
||||
regex: regexes.ascii.toString(),
|
||||
regex: regexes.ascii.source,
|
||||
description:
|
||||
"May only contain ASCII characters. See https://www.w3schools.com/charsets/ref_html_ascii.asp",
|
||||
}
|
||||
|
||||
export const email: Pattern = {
|
||||
regex: regexes.email.toString(),
|
||||
regex: regexes.email.source,
|
||||
description: "Must be a valid email address",
|
||||
}
|
||||
|
||||
export const base64: Pattern = {
|
||||
regex: regexes.base64.toString(),
|
||||
regex: regexes.base64.source,
|
||||
description:
|
||||
"May only contain base64 characters. See https://base64.guru/learn/base64-characters",
|
||||
}
|
||||
|
||||
8
sdk/base/package-lock.json
generated
8
sdk/base/package-lock.json
generated
@@ -14,7 +14,7 @@
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"ts-matches": "^6.1.0",
|
||||
"ts-matches": "^6.2.1",
|
||||
"yaml": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -3897,9 +3897,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-matches": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.1.0.tgz",
|
||||
"integrity": "sha512-01qvbIpOiKdbzzXDH84JeHunvCwBGFdZw94jS6kOGLSN5ms+1nBZtfe8WSuYMIPb1xPA+qyAiVgznFi2VCQ6UQ==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.2.1.tgz",
|
||||
"integrity": "sha512-qdnMgTHsGCEGGK6QiaNMY2vD9eQtRp2Q+pAxcOAzxHJKDKTBYsc1ISTg1zp8H2+EmtCB0eko/1TwYUA5/mUGug==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-morph": {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"ts-matches": "^6.1.0",
|
||||
"ts-matches": "^6.2.1",
|
||||
"yaml": "^2.2.2"
|
||||
},
|
||||
"prettier": {
|
||||
|
||||
@@ -102,7 +102,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
| "clearServiceInterfaces"
|
||||
| "bind"
|
||||
| "getHostInfo"
|
||||
| "getPrimaryUrl"
|
||||
type MainUsedEffects = "setMainStatus" | "setHealth"
|
||||
type CallbackEffects = "constRetry" | "clearCallbacks"
|
||||
type AlreadyExposed = "getSslCertificate" | "getSystemSmtp"
|
||||
@@ -379,7 +378,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
id: 'ui',
|
||||
description: 'The primary web app for this service.',
|
||||
type: 'ui',
|
||||
hasPrimary: false,
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
@@ -397,8 +395,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
id: string
|
||||
/** The human readable description. */
|
||||
description: string
|
||||
/** No effect until StartOS v0.4.0. If true, forces the user to select one URL (i.e. .onion, .local, or IP address) as the primary URL. This is needed by some services to function properly. */
|
||||
hasPrimary: boolean
|
||||
/** Affects how the interface appears to the user. One of: 'ui', 'api', 'p2p'. If 'ui', the user will see a "Launch UI" button */
|
||||
type: ServiceInterfaceType
|
||||
/** (optional) prepends the provided username to all URLs. */
|
||||
@@ -562,7 +558,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
id: 'primary-ui',
|
||||
description: 'The primary web app for this service.',
|
||||
type: 'ui',
|
||||
hasPrimary: false,
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
@@ -575,7 +570,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
id: 'admin-ui',
|
||||
description: 'The admin web app for this service.',
|
||||
type: 'ui',
|
||||
hasPrimary: false,
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
@@ -596,7 +590,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
id: 'api',
|
||||
description: 'The advanced API for this service.',
|
||||
type: 'api',
|
||||
hasPrimary: false,
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
@@ -688,6 +681,18 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
return Daemons.of<Manifest>({ effects, started, healthReceipts })
|
||||
},
|
||||
},
|
||||
SubContainer: {
|
||||
of(
|
||||
effects: Effects,
|
||||
image: {
|
||||
id: T.ImageId & keyof Manifest["images"]
|
||||
sharedRun?: boolean
|
||||
},
|
||||
name: string,
|
||||
) {
|
||||
return SubContainer.of(effects, image, name)
|
||||
},
|
||||
},
|
||||
List: {
|
||||
/**
|
||||
* @description Create a list of text inputs.
|
||||
@@ -1269,7 +1274,6 @@ export class StartSdk<Manifest extends T.SDKManifest, Store> {
|
||||
* @example default: 'radio1'
|
||||
*/
|
||||
default: keyof Variants & string
|
||||
required: boolean
|
||||
/**
|
||||
* @description A mapping of unique radio options to their human readable display format.
|
||||
* @example
|
||||
|
||||
@@ -60,51 +60,59 @@ export class CommandController {
|
||||
}
|
||||
return subc
|
||||
})()
|
||||
let childProcess: cp.ChildProcess
|
||||
if (options.runAsInit) {
|
||||
childProcess = await subc.launch(commands, {
|
||||
env: options.env,
|
||||
})
|
||||
} else {
|
||||
childProcess = await subc.spawn(commands, {
|
||||
env: options.env,
|
||||
stdio: options.onStdout || options.onStderr ? "pipe" : "inherit",
|
||||
|
||||
try {
|
||||
let childProcess: cp.ChildProcess
|
||||
if (options.runAsInit) {
|
||||
childProcess = await subc.launch(commands, {
|
||||
env: options.env,
|
||||
})
|
||||
} else {
|
||||
childProcess = await subc.spawn(commands, {
|
||||
env: options.env,
|
||||
stdio: options.onStdout || options.onStderr ? "pipe" : "inherit",
|
||||
})
|
||||
}
|
||||
|
||||
if (options.onStdout) childProcess.stdout?.on("data", options.onStdout)
|
||||
if (options.onStderr) childProcess.stderr?.on("data", options.onStderr)
|
||||
|
||||
const state = { exited: false }
|
||||
const answer = new Promise<null>((resolve, reject) => {
|
||||
childProcess.on("exit", (code) => {
|
||||
state.exited = true
|
||||
if (
|
||||
code === 0 ||
|
||||
code === 143 ||
|
||||
(code === null && childProcess.signalCode == "SIGTERM")
|
||||
) {
|
||||
return resolve(null)
|
||||
}
|
||||
if (code) {
|
||||
return reject(
|
||||
new Error(`${commands[0]} exited with code ${code}`),
|
||||
)
|
||||
} else {
|
||||
return reject(
|
||||
new Error(
|
||||
`${commands[0]} exited with signal ${childProcess.signalCode}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return new CommandController(
|
||||
answer,
|
||||
state,
|
||||
subc,
|
||||
childProcess,
|
||||
options.sigtermTimeout,
|
||||
)
|
||||
} catch (e) {
|
||||
await subc.destroy()
|
||||
throw e
|
||||
}
|
||||
|
||||
if (options.onStdout) childProcess.stdout?.on("data", options.onStdout)
|
||||
if (options.onStderr) childProcess.stderr?.on("data", options.onStderr)
|
||||
|
||||
const state = { exited: false }
|
||||
const answer = new Promise<null>((resolve, reject) => {
|
||||
childProcess.on("exit", (code) => {
|
||||
state.exited = true
|
||||
if (
|
||||
code === 0 ||
|
||||
code === 143 ||
|
||||
(code === null && childProcess.signalCode == "SIGTERM")
|
||||
) {
|
||||
return resolve(null)
|
||||
}
|
||||
if (code) {
|
||||
return reject(new Error(`${commands[0]} exited with code ${code}`))
|
||||
} else {
|
||||
return reject(
|
||||
new Error(
|
||||
`${commands[0]} exited with signal ${childProcess.signalCode}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return new CommandController(
|
||||
answer,
|
||||
state,
|
||||
subc,
|
||||
childProcess,
|
||||
options.sigtermTimeout,
|
||||
)
|
||||
}
|
||||
}
|
||||
get subContainerHandle() {
|
||||
@@ -121,7 +129,7 @@ export class CommandController {
|
||||
if (!this.state.exited) {
|
||||
this.process.kill("SIGKILL")
|
||||
}
|
||||
await this.subcontainer.destroy?.().catch((_) => {})
|
||||
await this.subcontainer.destroy().catch((_) => {})
|
||||
}
|
||||
}
|
||||
async term({ signal = SIGTERM, timeout = this.sigtermTimeout } = {}) {
|
||||
@@ -141,7 +149,7 @@ export class CommandController {
|
||||
|
||||
await this.runningAnswer
|
||||
} finally {
|
||||
await this.subcontainer.destroy?.()
|
||||
await this.subcontainer.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,8 @@ export class Daemon {
|
||||
let timeoutCounter = 0
|
||||
new Promise(async () => {
|
||||
while (this.shouldBeRunning) {
|
||||
if (this.commandController)
|
||||
await this.commandController.term().catch((err) => console.error(err))
|
||||
this.commandController = await this.startCommand()
|
||||
await this.commandController.wait().catch((err) => console.error(err))
|
||||
await new Promise((resolve) => setTimeout(resolve, timeoutCounter))
|
||||
|
||||
@@ -5,7 +5,7 @@ import { HealthCheckResult } from "../health/checkFns"
|
||||
import { Trigger } from "../trigger"
|
||||
import * as T from "../../../base/lib/types"
|
||||
import { Mounts } from "./Mounts"
|
||||
import { ExecSpawnable, MountOptions } from "../util/SubContainer"
|
||||
import { ExecSpawnable, MountOptions, SubContainer } from "../util/SubContainer"
|
||||
|
||||
import { promisify } from "node:util"
|
||||
import * as CP from "node:child_process"
|
||||
@@ -49,16 +49,18 @@ type DaemonsParams<
|
||||
> = {
|
||||
/** The command line command to start the daemon */
|
||||
command: T.CommandType
|
||||
/** Information about the image in which the daemon runs */
|
||||
image: {
|
||||
/** The ID of the image. Must be one of the image IDs declared in the manifest */
|
||||
id: keyof Manifest["images"] & T.ImageId
|
||||
/**
|
||||
* Whether or not to share the `/run` directory with the parent container.
|
||||
* This is useful if you are trying to connect to a service that exposes a unix domain socket or auth cookie via the `/run` directory
|
||||
*/
|
||||
sharedRun?: boolean
|
||||
}
|
||||
/** Information about the subcontainer in which the daemon runs */
|
||||
subcontainer:
|
||||
| {
|
||||
/** The ID of the image. Must be one of the image IDs declared in the manifest */
|
||||
id: keyof Manifest["images"] & T.ImageId
|
||||
/**
|
||||
* Whether or not to share the `/run` directory with the parent container.
|
||||
* This is useful if you are trying to connect to a service that exposes a unix domain socket or auth cookie via the `/run` directory
|
||||
*/
|
||||
sharedRun?: boolean
|
||||
}
|
||||
| SubContainer
|
||||
/** For mounting the necessary volumes. Syntax: sdk.Mounts.of().addVolume() */
|
||||
mounts: Mounts<Manifest>
|
||||
env?: Record<string, string>
|
||||
@@ -147,11 +149,16 @@ export class Daemons<Manifest extends T.SDKManifest, Ids extends string>
|
||||
options: DaemonsParams<Manifest, Ids, Command, Id>,
|
||||
) {
|
||||
const daemonIndex = this.daemons.length
|
||||
const daemon = Daemon.of()(this.effects, options.image, options.command, {
|
||||
...options,
|
||||
mounts: options.mounts.build(),
|
||||
subcontainerName: id,
|
||||
})
|
||||
const daemon = Daemon.of()(
|
||||
this.effects,
|
||||
options.subcontainer,
|
||||
options.command,
|
||||
{
|
||||
...options,
|
||||
mounts: options.mounts.build(),
|
||||
subcontainerName: id,
|
||||
},
|
||||
)
|
||||
const healthDaemon = new HealthDaemon(
|
||||
daemon,
|
||||
daemonIndex,
|
||||
@@ -178,14 +185,18 @@ export class Daemons<Manifest extends T.SDKManifest, Ids extends string>
|
||||
}
|
||||
|
||||
async build() {
|
||||
this.updateMainHealth()
|
||||
this.healthDaemons.forEach((x) =>
|
||||
x.addWatcher(() => this.updateMainHealth()),
|
||||
)
|
||||
const built = {
|
||||
term: async (options?: { signal?: Signals; timeout?: number }) => {
|
||||
term: async () => {
|
||||
try {
|
||||
await Promise.all(this.healthDaemons.map((x) => x.term(options)))
|
||||
for (let result of await Promise.allSettled(
|
||||
this.healthDaemons.map((x) =>
|
||||
x.term({ timeout: x.sigtermTimeout }),
|
||||
),
|
||||
)) {
|
||||
if (result.status === "rejected") {
|
||||
console.error(result.reason)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.effects.setMainStatus({ status: "stopped" })
|
||||
}
|
||||
@@ -194,8 +205,4 @@ export class Daemons<Manifest extends T.SDKManifest, Ids extends string>
|
||||
this.started(() => built.term())
|
||||
return built
|
||||
}
|
||||
|
||||
private updateMainHealth() {
|
||||
this.effects.setMainStatus({ status: "running" })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ export class HealthDaemon {
|
||||
private _health: HealthCheckResult = { result: "starting", message: null }
|
||||
private healthWatchers: Array<() => unknown> = []
|
||||
private running = false
|
||||
private resolveReady: (() => void) | undefined
|
||||
private readyPromise: Promise<void>
|
||||
constructor(
|
||||
private readonly daemon: Promise<Daemon>,
|
||||
readonly daemonIndex: number,
|
||||
@@ -35,6 +37,7 @@ export class HealthDaemon {
|
||||
readonly effects: Effects,
|
||||
readonly sigtermTimeout: number = DEFAULT_SIGTERM_TIMEOUT,
|
||||
) {
|
||||
this.readyPromise = new Promise((resolve) => (this.resolveReady = resolve))
|
||||
this.updateStatus()
|
||||
this.dependencies.forEach((d) => d.addWatcher(() => this.updateStatus()))
|
||||
}
|
||||
@@ -112,6 +115,12 @@ export class HealthDaemon {
|
||||
message: "message" in err ? err.message : String(err),
|
||||
}
|
||||
})
|
||||
if (
|
||||
this.resolveReady &&
|
||||
(response.result === "success" || response.result === "disabled")
|
||||
) {
|
||||
this.resolveReady()
|
||||
}
|
||||
await this.setHealth(response)
|
||||
} else {
|
||||
await this.setHealth({
|
||||
@@ -129,6 +138,10 @@ export class HealthDaemon {
|
||||
}
|
||||
}
|
||||
|
||||
onReady() {
|
||||
return this.readyPromise
|
||||
}
|
||||
|
||||
private async setHealth(health: HealthCheckResult) {
|
||||
this._health = health
|
||||
this.healthWatchers.forEach((watcher) => watcher())
|
||||
|
||||
@@ -26,16 +26,6 @@ export function setupManifest<
|
||||
return manifest
|
||||
}
|
||||
|
||||
function gitHash(): string {
|
||||
const hash = execSync("git rev-parse HEAD").toString().trim()
|
||||
try {
|
||||
execSync("git diff-index --quiet HEAD --")
|
||||
return hash
|
||||
} catch (e) {
|
||||
return hash + "-modified"
|
||||
}
|
||||
}
|
||||
|
||||
export function buildManifest<
|
||||
Id extends string,
|
||||
Version extends string,
|
||||
@@ -68,7 +58,6 @@ export function buildManifest<
|
||||
)
|
||||
return {
|
||||
...manifest,
|
||||
gitHash: gitHash(),
|
||||
osVersion: SDKVersion,
|
||||
version: versions.current.options.version,
|
||||
releaseNotes: versions.current.options.releaseNotes,
|
||||
|
||||
@@ -15,7 +15,6 @@ describe("host", () => {
|
||||
name: "Foo",
|
||||
id: "foo",
|
||||
description: "A Foo",
|
||||
hasPrimary: false,
|
||||
type: "ui",
|
||||
username: "bar",
|
||||
path: "/baz",
|
||||
|
||||
12
sdk/package/package-lock.json
generated
12
sdk/package/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-beta.0",
|
||||
"version": "0.3.6-beta.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-beta.0",
|
||||
"version": "0.3.6-beta.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
@@ -15,7 +15,7 @@
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"ts-matches": "^6.1.0",
|
||||
"ts-matches": "^6.2.1",
|
||||
"yaml": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -3918,9 +3918,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ts-matches": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.1.0.tgz",
|
||||
"integrity": "sha512-01qvbIpOiKdbzzXDH84JeHunvCwBGFdZw94jS6kOGLSN5ms+1nBZtfe8WSuYMIPb1xPA+qyAiVgznFi2VCQ6UQ==",
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-matches/-/ts-matches-6.2.1.tgz",
|
||||
"integrity": "sha512-qdnMgTHsGCEGGK6QiaNMY2vD9eQtRp2Q+pAxcOAzxHJKDKTBYsc1ISTg1zp8H2+EmtCB0eko/1TwYUA5/mUGug==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-morph": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-beta.0",
|
||||
"version": "0.3.6-beta.3",
|
||||
"description": "Software development kit to facilitate packaging services for StartOS",
|
||||
"main": "./package/lib/index.js",
|
||||
"types": "./package/lib/index.d.ts",
|
||||
@@ -33,7 +33,7 @@
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"mime-types": "^2.1.35",
|
||||
"ts-matches": "^6.1.0",
|
||||
"ts-matches": "^6.2.1",
|
||||
"yaml": "^2.2.2",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@noble/curves": "^1.4.0",
|
||||
|
||||
Reference in New Issue
Block a user