mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Gateways, domains, and new service interface (#3001)
* add support for inbound proxies * backend changes * fix file type * proxy -> tunnel, implement backend apis * wip start-tunneld * add domains and gateways, remove routers, fix docs links * dont show hidden actions * show and test dns * edit instead of chnage acme and change gateway * refactor: domains page * refactor: gateways page * domains and acme refactor * certificate authorities * refactor public/private gateways * fix fe types * domains mostly finished * refactor: add file control to form service * add ip util to sdk * domains api + migration * start service interface page, WIP * different options for clearnet domains * refactor: styles for interfaces page * minor * better placeholder for no addresses * start sorting addresses * best address logic * comments * fix unnecessary export * MVP of service interface page * domains preferred * fix: address comments * only translations left * wip: start-tunnel & fix build * forms for adding domain, rework things based on new ideas * fix: dns testing * public domain, max width, descriptions for dns * nix StartOS domains, implement public and private domains at interface scope * restart tor instead of reset * better icon for restart tor * dns * fix sort functions for public and private domains * with todos * update types * clean up tech debt, bump dependencies * revert to ts-rs v9 * fix all types * fix dns form * add missing translations * it builds * fix: comments (#3009) * fix: comments * undo default --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix: refactor legacy components (#3010) * fix: comments * fix: refactor legacy components * remove default again --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * more translations * wip * fix deadlock * coukd work * simple renaming * placeholder for empty service interfaces table * honor hidden form values * remove logs * reason instead of description * fix dns * misc fixes * implement toggling gateways for service interface * fix showing dns records * move status column in service list * remove unnecessary truthy check * refactor: refactor forms components and remove legacy Taiga UI package (#3012) * handle wh file uploads * wip: debugging tor * socks5 proxy working * refactor: fix multiple comments (#3013) * refactor: fix multiple comments * styling changes, add documentation to sidebar * translations for dns page * refactor: subtle colors * rearrange service page --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix file_stream and remove non-terminating test * clean up logs * support for sccache * fix gha sccache * more marketplace translations * install wizard clarity * stub hostnameInfo in migration * fix address info after setup, fix styling on SI page, new 040 release notes * remove tor logs from os * misc fixes * reset tor still not functioning... * update ts * minor styling and wording * chore: some fixes (#3015) * fix gateway renames * different handling for public domains * styling fixes * whole navbar should not be clickable on service show page * timeout getState request * remove links from changelog * misc fixes from pairing * use custom name for gateway in more places * fix dns parsing * closes #3003 * closes #2999 * chore: some fixes (#3017) * small copy change * revert hardcoded error for testing * dont require port forward if gateway is public * use old wan ip when not available * fix .const hanging on undefined * fix test * fix doc test * fix renames * update deps * allow specifying dependency metadata directly * temporarily make dependencies not cliackable in marketplace listings * fix socks bind * fix test --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: waterplea <alexander@inkin.ru>
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
/** Used to reach out from the pure js runtime */
|
||||
|
||||
export type Effects = {
|
||||
readonly eventId: string | null
|
||||
child: (name: string) => Effects
|
||||
constRetry?: () => void
|
||||
isInContext: boolean
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ExtractInputSpecType, InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { List } from "./list"
|
||||
import { UnionRes, UnionResStaticValidatedAs, Variants } from "./variants"
|
||||
import {
|
||||
FilePath,
|
||||
Pattern,
|
||||
RandomString,
|
||||
ValueSpec,
|
||||
@@ -27,6 +26,12 @@ import {
|
||||
} from "ts-matches"
|
||||
import { DeepPartial } from "../../../types"
|
||||
|
||||
export const fileInfoParser = object({
|
||||
path: string,
|
||||
commitment: object({ hash: string, size: number }),
|
||||
})
|
||||
export type FileInfo = typeof fileInfoParser._TYPE
|
||||
|
||||
type AsRequired<T, Required extends boolean> = Required extends true
|
||||
? T
|
||||
: T | null
|
||||
@@ -891,47 +896,54 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
}
|
||||
}, spec.validator)
|
||||
}
|
||||
// static file<Store, Required extends boolean>(a: {
|
||||
// name: string
|
||||
// description?: string | null
|
||||
// extensions: string[]
|
||||
// required: Required
|
||||
// }) {
|
||||
// const buildValue = {
|
||||
// type: "file" as const,
|
||||
// description: null,
|
||||
// warning: null,
|
||||
// ...a,
|
||||
// }
|
||||
// return new Value<AsRequired<FilePath, Required>, Store>(
|
||||
// () => ({
|
||||
// ...buildValue,
|
||||
// }),
|
||||
// asRequiredParser(object({ filePath: string }), a),
|
||||
// )
|
||||
// }
|
||||
// static dynamicFile<Store>(
|
||||
// a: LazyBuild<
|
||||
// Store,
|
||||
// {
|
||||
// name: string
|
||||
// description?: string | null
|
||||
// warning?: string | null
|
||||
// extensions: string[]
|
||||
// required: boolean
|
||||
// }
|
||||
// >,
|
||||
// ) {
|
||||
// return new Value<FilePath | null, Store>(
|
||||
// async (options) => ({
|
||||
// type: "file" as const,
|
||||
// description: null,
|
||||
// warning: null,
|
||||
// ...(await a(options)),
|
||||
// }),
|
||||
// object({ filePath: string }).nullable(),
|
||||
// )
|
||||
// }
|
||||
static file<Required extends boolean>(a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
}) {
|
||||
const buildValue = {
|
||||
type: "file" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...a,
|
||||
}
|
||||
return new Value<AsRequired<FileInfo, Required>>(
|
||||
() => ({
|
||||
spec: {
|
||||
...buildValue,
|
||||
},
|
||||
validator: asRequiredParser(fileInfoParser, a),
|
||||
}),
|
||||
asRequiredParser(fileInfoParser, a),
|
||||
)
|
||||
}
|
||||
static dynamicFile<Required extends boolean>(
|
||||
a: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
}>,
|
||||
) {
|
||||
return new Value<AsRequired<FileInfo, Required>, FileInfo | null>(
|
||||
async (options) => {
|
||||
const spec = {
|
||||
type: "file" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...(await a(options)),
|
||||
}
|
||||
return {
|
||||
spec,
|
||||
validator: asRequiredParser(fileInfoParser, spec),
|
||||
}
|
||||
},
|
||||
fileInfoParser.nullable(),
|
||||
)
|
||||
}
|
||||
/**
|
||||
* @description Displays a dropdown, allowing for a single selection. Depending on the selection, a different object ("sub form") is presented.
|
||||
* @example
|
||||
|
||||
@@ -66,9 +66,6 @@ export type ValueSpecTextarea = {
|
||||
immutable: boolean
|
||||
}
|
||||
|
||||
export type FilePath = {
|
||||
filePath: string
|
||||
}
|
||||
export type ValueSpecNumber = {
|
||||
type: "number"
|
||||
min: number | null
|
||||
|
||||
@@ -5,9 +5,11 @@ import { once } from "../util"
|
||||
import { InitScript } from "../inits"
|
||||
import { Parser } from "ts-matches"
|
||||
|
||||
type MaybeInputSpec<Type> = {} extends Type ? null : InputSpec<Type>
|
||||
export type Run<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
input: A
|
||||
spec: T.inputSpecTypes.InputSpec
|
||||
}) => Promise<(T.ActionResult & { version: "1" }) | null | void | undefined>
|
||||
export type GetInput<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
@@ -47,11 +49,14 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
implements ActionInfo<Id, Type>
|
||||
{
|
||||
readonly _INPUT: Type = null as any as Type
|
||||
private cachedParser?: Parser<unknown, Type>
|
||||
private prevInputSpec: Record<
|
||||
string,
|
||||
{ spec: T.inputSpecTypes.InputSpec; validator: Parser<unknown, Type> }
|
||||
> = {}
|
||||
private constructor(
|
||||
readonly id: Id,
|
||||
private readonly metadataFn: MaybeFn<T.ActionMetadata>,
|
||||
private readonly inputSpec: InputSpec<Type>,
|
||||
private readonly inputSpec: MaybeInputSpec<Type>,
|
||||
private readonly getInputFn: GetInput<Type>,
|
||||
private readonly runFn: Run<Type>,
|
||||
) {}
|
||||
@@ -81,7 +86,7 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
return new Action(
|
||||
id,
|
||||
mapMaybeFn(metadata, (m) => ({ ...m, hasInput: false })),
|
||||
InputSpec.of({}),
|
||||
null,
|
||||
async () => null,
|
||||
run,
|
||||
)
|
||||
@@ -100,10 +105,15 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
return metadata
|
||||
}
|
||||
async getInput(options: { effects: T.Effects }): Promise<T.ActionInput> {
|
||||
const built = await this.inputSpec.build(options)
|
||||
this.cachedParser = built.validator
|
||||
let spec = {}
|
||||
if (this.inputSpec) {
|
||||
const built = await this.inputSpec.build(options)
|
||||
this.prevInputSpec[options.effects.eventId!] = built
|
||||
spec = built.spec
|
||||
}
|
||||
return {
|
||||
spec: built.spec,
|
||||
eventId: options.effects.eventId!,
|
||||
spec,
|
||||
value:
|
||||
((await this.getInputFn(options)) as
|
||||
| Record<string, unknown>
|
||||
@@ -115,15 +125,23 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
effects: T.Effects
|
||||
input: Type
|
||||
}): Promise<T.ActionResult | null> {
|
||||
const parser =
|
||||
this.cachedParser ?? (await this.inputSpec.build(options)).validator
|
||||
let spec = {}
|
||||
if (this.inputSpec) {
|
||||
const prevInputSpec = this.prevInputSpec[options.effects.eventId!]
|
||||
if (!prevInputSpec) {
|
||||
throw new Error(
|
||||
`getActionInput has not been called for EventID ${options.effects.eventId}`,
|
||||
)
|
||||
}
|
||||
options.input = prevInputSpec.validator.unsafeCast(options.input)
|
||||
spec = prevInputSpec.spec
|
||||
}
|
||||
return (
|
||||
(await this.runFn({
|
||||
effects: options.effects,
|
||||
input: this.cachedParser
|
||||
? this.cachedParser.unsafeCast(options.input)
|
||||
: options.input,
|
||||
})) || null
|
||||
input: options.input,
|
||||
spec,
|
||||
})) ?? null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function checkDependencies<
|
||||
}
|
||||
const tasksSatisfied = (packageId: DependencyId) =>
|
||||
Object.entries(infoFor(packageId).result.tasks).filter(
|
||||
([_, t]) => t.active && t.task.severity === "critical",
|
||||
([_, t]) => t?.active && t.task.severity === "critical",
|
||||
).length === 0
|
||||
const healthCheckSatisfied = (
|
||||
packageId: DependencyId,
|
||||
@@ -146,7 +146,7 @@ export async function checkDependencies<
|
||||
const throwIfTasksNotSatisfied = (packageId: DependencyId) => {
|
||||
const dep = infoFor(packageId)
|
||||
const reqs = Object.entries(dep.result.tasks)
|
||||
.filter(([_, t]) => t.active && t.task.severity === "critical")
|
||||
.filter(([_, t]) => t?.active && t.task.severity === "critical")
|
||||
.map(([id, _]) => id)
|
||||
if (reqs.length) {
|
||||
throw new Error(
|
||||
|
||||
@@ -2,7 +2,10 @@ import * as T from "../types"
|
||||
import { once } from "../util"
|
||||
|
||||
export type RequiredDependenciesOf<Manifest extends T.SDKManifest> = {
|
||||
[K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false
|
||||
[K in keyof Manifest["dependencies"]]: Exclude<
|
||||
Manifest["dependencies"][K],
|
||||
undefined
|
||||
>["optional"] extends false
|
||||
? K
|
||||
: never
|
||||
}[keyof Manifest["dependencies"]]
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Guid } from "./Guid"
|
||||
|
||||
export type ActionInput = {
|
||||
eventId: Guid
|
||||
spec: Record<string, unknown>
|
||||
value: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
@@ -1,3 +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 }
|
||||
export type AddTunnelParams = { name: string; config: string; public: boolean }
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type BindingGatewaySetEnabledParams = {
|
||||
internalPort: number
|
||||
gateway: GatewayId
|
||||
enabled: boolean | null
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { PathOrUrl } from "./PathOrUrl"
|
||||
import type { MetadataSrc } from "./MetadataSrc"
|
||||
|
||||
export type DepInfo = {
|
||||
description: string | null
|
||||
optional: boolean
|
||||
s9pk: PathOrUrl | null
|
||||
}
|
||||
} & MetadataSrc
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type NetworkInterfaceSetInboundParams = {
|
||||
interface: string
|
||||
inbound: boolean | null
|
||||
export type DnsSettings = {
|
||||
dhcpServers: Array<string>
|
||||
staticServers: Array<string> | null
|
||||
}
|
||||
4
sdk/base/lib/osBindings/DomainSettings.ts
Normal file
4
sdk/base/lib/osBindings/DomainSettings.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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type DomainSettings = { gateway: GatewayId }
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Guid } from "./Guid"
|
||||
|
||||
export type ProcedureId = { procedureId: Guid }
|
||||
export type EventId = { eventId: Guid }
|
||||
4
sdk/base/lib/osBindings/ForgetGatewayParams.ts
Normal file
4
sdk/base/lib/osBindings/ForgetGatewayParams.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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type ForgetGatewayParams = { gateway: GatewayId }
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type UnsetInboundParams = { interface: string }
|
||||
export type GatewayId = string
|
||||
@@ -1,12 +1,13 @@
|
||||
// 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 { DomainConfig } from "./DomainConfig"
|
||||
import type { HostnameInfo } from "./HostnameInfo"
|
||||
import type { PublicDomainConfig } from "./PublicDomainConfig"
|
||||
|
||||
export type Host = {
|
||||
bindings: { [key: number]: BindInfo }
|
||||
onions: string[]
|
||||
domains: { [key: string]: DomainConfig }
|
||||
publicDomains: { [key: string]: PublicDomainConfig }
|
||||
privateDomains: Array<string>
|
||||
/**
|
||||
* COMPUTED: NetService::update
|
||||
*/
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// 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 HostAddress =
|
||||
| { kind: "onion"; address: string }
|
||||
| {
|
||||
kind: "domain"
|
||||
address: string
|
||||
public: boolean
|
||||
acme: AcmeProvider | null
|
||||
}
|
||||
@@ -3,10 +3,5 @@ import type { IpHostname } from "./IpHostname"
|
||||
import type { OnionHostname } from "./OnionHostname"
|
||||
|
||||
export type HostnameInfo =
|
||||
| {
|
||||
kind: "ip"
|
||||
networkInterfaceId: string
|
||||
public: boolean
|
||||
hostname: IpHostname
|
||||
}
|
||||
| { kind: "ip"; gatewayId: string; public: boolean; hostname: IpHostname }
|
||||
| { kind: "onion"; hostname: OnionHostname }
|
||||
|
||||
@@ -17,8 +17,7 @@ export type IpHostname =
|
||||
}
|
||||
| {
|
||||
kind: "domain"
|
||||
domain: string
|
||||
subdomain: string | null
|
||||
value: string
|
||||
port: number | null
|
||||
sslPort: number | null
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ export type IpInfo = {
|
||||
scopeId: number
|
||||
deviceType: NetworkInterfaceType | null
|
||||
subnets: string[]
|
||||
lanIp: string[]
|
||||
wanIp: string | null
|
||||
ntpServers: string[]
|
||||
dnsServers: string[]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { PasswordType } from "./PasswordType"
|
||||
|
||||
export type LoginParams = { password: PasswordType | null; ephemeral: boolean }
|
||||
export type LoginParams = { password: string; ephemeral: boolean }
|
||||
|
||||
4
sdk/base/lib/osBindings/Metadata.ts
Normal file
4
sdk/base/lib/osBindings/Metadata.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 { PathOrUrl } from "./PathOrUrl"
|
||||
|
||||
export type Metadata = { title: string; icon: PathOrUrl }
|
||||
5
sdk/base/lib/osBindings/MetadataSrc.ts
Normal file
5
sdk/base/lib/osBindings/MetadataSrc.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Metadata } from "./Metadata"
|
||||
import type { PathOrUrl } from "./PathOrUrl"
|
||||
|
||||
export type MetadataSrc = { metadata: Metadata } | { s9pk: PathOrUrl | null }
|
||||
@@ -1,7 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type NetInfo = {
|
||||
public: boolean
|
||||
privateDisabled: Array<GatewayId>
|
||||
publicEnabled: Array<GatewayId>
|
||||
assignedPort: number | null
|
||||
assignedSslPort: number | null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// 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 { DnsSettings } from "./DnsSettings"
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
import type { Host } from "./Host"
|
||||
import type { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
|
||||
import type { WifiInfo } from "./WifiInfo"
|
||||
@@ -8,6 +10,7 @@ import type { WifiInfo } from "./WifiInfo"
|
||||
export type NetworkInfo = {
|
||||
wifi: WifiInfo
|
||||
host: Host
|
||||
networkInterfaces: { [key: string]: NetworkInterfaceInfo }
|
||||
gateways: { [key: GatewayId]: NetworkInterfaceInfo }
|
||||
acme: { [key: AcmeProvider]: AcmeSettings }
|
||||
dns: DnsSettings
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import type { IpInfo } from "./IpInfo"
|
||||
|
||||
export type NetworkInterfaceInfo = {
|
||||
inbound: boolean | null
|
||||
outbound: boolean | null
|
||||
name: string | null
|
||||
public: boolean | null
|
||||
secure: boolean | null
|
||||
ipInfo: IpInfo | null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { GatewayId } from "./GatewayId"
|
||||
|
||||
export type BindingSetPublicParams = {
|
||||
internalPort: number
|
||||
export type NetworkInterfaceSetPublicParams = {
|
||||
gateway: GatewayId
|
||||
public: boolean | null
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import type { DataUrl } from "./DataUrl"
|
||||
import type { Hosts } from "./Hosts"
|
||||
import type { MainStatus } from "./MainStatus"
|
||||
import type { PackageState } from "./PackageState"
|
||||
import type { ReplayId } from "./ReplayId"
|
||||
import type { ServiceInterface } from "./ServiceInterface"
|
||||
import type { ServiceInterfaceId } from "./ServiceInterfaceId"
|
||||
import type { TaskEntry } from "./TaskEntry"
|
||||
@@ -20,7 +21,7 @@ export type PackageDataEntry = {
|
||||
lastBackup: string | null
|
||||
currentDependencies: CurrentDependencies
|
||||
actions: { [key: ActionId]: ActionMetadata }
|
||||
tasks: { [key: string]: TaskEntry }
|
||||
tasks: { [key: ReplayId]: TaskEntry }
|
||||
serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterface }
|
||||
hosts: Hosts
|
||||
storeExposedDependents: string[]
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// 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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type DomainConfig = { public: boolean; acme: AcmeProvider | null }
|
||||
export type PublicDomainConfig = {
|
||||
gateway: GatewayId
|
||||
acme: AcmeProvider | null
|
||||
}
|
||||
4
sdk/base/lib/osBindings/RemoveTunnelParams.ts
Normal file
4
sdk/base/lib/osBindings/RemoveTunnelParams.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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type RemoveTunnelParams = { id: GatewayId }
|
||||
4
sdk/base/lib/osBindings/RenameGatewayParams.ts
Normal file
4
sdk/base/lib/osBindings/RenameGatewayParams.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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type RenameGatewayParams = { id: GatewayId; name: string }
|
||||
@@ -1,9 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Session } from "./Session"
|
||||
|
||||
export type Sessions = {
|
||||
[key: string]: {
|
||||
loggedIn: string
|
||||
lastActive: string
|
||||
userAgent: string | null
|
||||
}
|
||||
}
|
||||
export type Sessions = { [key: string]: Session }
|
||||
|
||||
4
sdk/base/lib/osBindings/UnsetPublicParams.ts
Normal file
4
sdk/base/lib/osBindings/UnsetPublicParams.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 { GatewayId } from "./GatewayId"
|
||||
|
||||
export type UnsetPublicParams = { gateway: GatewayId }
|
||||
@@ -17,6 +17,7 @@ export { AddPackageParams } from "./AddPackageParams"
|
||||
export { AddPackageToCategoryParams } from "./AddPackageToCategoryParams"
|
||||
export { AddressInfo } from "./AddressInfo"
|
||||
export { AddSslOptions } from "./AddSslOptions"
|
||||
export { AddTunnelParams } from "./AddTunnelParams"
|
||||
export { AddVersionParams } from "./AddVersionParams"
|
||||
export { Alerts } from "./Alerts"
|
||||
export { Algorithm } from "./Algorithm"
|
||||
@@ -33,7 +34,7 @@ export { BackupTargetFS } from "./BackupTargetFS"
|
||||
export { Base64 } from "./Base64"
|
||||
export { BindId } from "./BindId"
|
||||
export { BindInfo } from "./BindInfo"
|
||||
export { BindingSetPublicParams } from "./BindingSetPublicParams"
|
||||
export { BindingGatewaySetEnabledParams } from "./BindingGatewaySetEnabledParams"
|
||||
export { BindOptions } from "./BindOptions"
|
||||
export { BindParams } from "./BindParams"
|
||||
export { Blake3Commitment } from "./Blake3Commitment"
|
||||
@@ -65,17 +66,20 @@ export { DepInfo } from "./DepInfo"
|
||||
export { Description } from "./Description"
|
||||
export { DestroySubcontainerFsParams } from "./DestroySubcontainerFsParams"
|
||||
export { DeviceFilter } from "./DeviceFilter"
|
||||
export { DomainConfig } from "./DomainConfig"
|
||||
export { DnsSettings } from "./DnsSettings"
|
||||
export { DomainSettings } from "./DomainSettings"
|
||||
export { Duration } from "./Duration"
|
||||
export { EchoParams } from "./EchoParams"
|
||||
export { EditSignerParams } from "./EditSignerParams"
|
||||
export { EncryptedWire } from "./EncryptedWire"
|
||||
export { EventId } from "./EventId"
|
||||
export { ExportActionParams } from "./ExportActionParams"
|
||||
export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams"
|
||||
export { FileType } from "./FileType"
|
||||
export { ForgetInterfaceParams } from "./ForgetInterfaceParams"
|
||||
export { ForgetGatewayParams } from "./ForgetGatewayParams"
|
||||
export { FullIndex } from "./FullIndex"
|
||||
export { FullProgress } from "./FullProgress"
|
||||
export { GatewayId } from "./GatewayId"
|
||||
export { GetActionInputParams } from "./GetActionInputParams"
|
||||
export { GetContainerIpParams } from "./GetContainerIpParams"
|
||||
export { GetHostInfoParams } from "./GetHostInfoParams"
|
||||
@@ -96,7 +100,6 @@ 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 { HostnameInfo } from "./HostnameInfo"
|
||||
export { Hosts } from "./Hosts"
|
||||
@@ -125,6 +128,8 @@ export { Manifest } from "./Manifest"
|
||||
export { MaybeUtf8String } from "./MaybeUtf8String"
|
||||
export { MebiBytes } from "./MebiBytes"
|
||||
export { MerkleArchiveCommitment } from "./MerkleArchiveCommitment"
|
||||
export { MetadataSrc } from "./MetadataSrc"
|
||||
export { Metadata } from "./Metadata"
|
||||
export { MetricsCpu } from "./MetricsCpu"
|
||||
export { MetricsDisk } from "./MetricsDisk"
|
||||
export { MetricsGeneral } from "./MetricsGeneral"
|
||||
@@ -137,7 +142,7 @@ export { NamedProgress } from "./NamedProgress"
|
||||
export { NetInfo } from "./NetInfo"
|
||||
export { NetworkInfo } from "./NetworkInfo"
|
||||
export { NetworkInterfaceInfo } from "./NetworkInterfaceInfo"
|
||||
export { NetworkInterfaceSetInboundParams } from "./NetworkInterfaceSetInboundParams"
|
||||
export { NetworkInterfaceSetPublicParams } from "./NetworkInterfaceSetPublicParams"
|
||||
export { NetworkInterfaceType } from "./NetworkInterfaceType"
|
||||
export { OnionHostname } from "./OnionHostname"
|
||||
export { OsIndex } from "./OsIndex"
|
||||
@@ -155,9 +160,9 @@ export { PackageVersionInfo } from "./PackageVersionInfo"
|
||||
export { PasswordType } from "./PasswordType"
|
||||
export { PathOrUrl } from "./PathOrUrl"
|
||||
export { Percentage } from "./Percentage"
|
||||
export { ProcedureId } from "./ProcedureId"
|
||||
export { Progress } from "./Progress"
|
||||
export { ProgressUnits } from "./ProgressUnits"
|
||||
export { PublicDomainConfig } from "./PublicDomainConfig"
|
||||
export { Public } from "./Public"
|
||||
export { RecoverySource } from "./RecoverySource"
|
||||
export { RegistryAsset } from "./RegistryAsset"
|
||||
@@ -167,7 +172,9 @@ export { RemoveAssetParams } from "./RemoveAssetParams"
|
||||
export { RemoveCategoryParams } from "./RemoveCategoryParams"
|
||||
export { RemovePackageFromCategoryParams } from "./RemovePackageFromCategoryParams"
|
||||
export { RemovePackageParams } from "./RemovePackageParams"
|
||||
export { RemoveTunnelParams } from "./RemoveTunnelParams"
|
||||
export { RemoveVersionParams } from "./RemoveVersionParams"
|
||||
export { RenameGatewayParams } from "./RenameGatewayParams"
|
||||
export { ReplayId } from "./ReplayId"
|
||||
export { RequestCommitment } from "./RequestCommitment"
|
||||
export { RunActionParams } from "./RunActionParams"
|
||||
@@ -203,7 +210,7 @@ export { TaskSeverity } from "./TaskSeverity"
|
||||
export { TaskTrigger } from "./TaskTrigger"
|
||||
export { Task } from "./Task"
|
||||
export { TestSmtpParams } from "./TestSmtpParams"
|
||||
export { UnsetInboundParams } from "./UnsetInboundParams"
|
||||
export { UnsetPublicParams } from "./UnsetPublicParams"
|
||||
export { UpdatingState } from "./UpdatingState"
|
||||
export { VerifyCifsParams } from "./VerifyCifsParams"
|
||||
export { VersionSignerParams } from "./VersionSignerParams"
|
||||
|
||||
@@ -101,18 +101,20 @@ export class S9pk {
|
||||
)
|
||||
}
|
||||
|
||||
async dependencyMetadata(): Promise<Record<PackageId, DependencyMetadata>> {
|
||||
async dependencyMetadata() {
|
||||
return Object.fromEntries(
|
||||
await Promise.all(
|
||||
Object.entries(this.manifest.dependencies).map(async ([id, info]) => [
|
||||
id,
|
||||
{
|
||||
...(await this.dependencyMetadataFor(id)),
|
||||
icon: await this.dependencyIconFor(id),
|
||||
description: info.description,
|
||||
optional: info.optional,
|
||||
},
|
||||
]),
|
||||
Object.entries(this.manifest.dependencies)
|
||||
.filter(([_, info]) => !!info)
|
||||
.map(async ([id, info]) => [
|
||||
id,
|
||||
{
|
||||
...(await this.dependencyMetadataFor(id)),
|
||||
icon: await this.dependencyIconFor(id),
|
||||
description: info!.description,
|
||||
optional: info!.optional,
|
||||
},
|
||||
]),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ type EffectsTypeChecker<T extends StringObject = Effects> = {
|
||||
describe("startosTypeValidation ", () => {
|
||||
test(`checking the params match`, () => {
|
||||
typeEquality<EffectsTypeChecker>({
|
||||
eventId: {} as never,
|
||||
child: "",
|
||||
isInContext: {} as never,
|
||||
onLeaveContext: () => {},
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { HostnameInfo } from "../types"
|
||||
|
||||
export function hostnameInfoToAddress(hostInfo: HostnameInfo): string {
|
||||
if (hostInfo.kind === "onion") {
|
||||
return `${hostInfo.hostname.value}`
|
||||
}
|
||||
if (hostInfo.kind !== "ip") {
|
||||
throw Error("Expecting that the kind is ip.")
|
||||
}
|
||||
const hostname = hostInfo.hostname
|
||||
if (hostname.kind === "domain") {
|
||||
return `${hostname.subdomain ? `${hostname.subdomain}.` : ""}${hostname.domain}`
|
||||
}
|
||||
const port = hostname.sslPort || hostname.port
|
||||
const portString = port ? `:${port}` : ""
|
||||
if ("ipv4" === hostname.kind || "ipv6" === hostname.kind) {
|
||||
return `${hostname.value}${portString}`
|
||||
}
|
||||
if ("local" === hostname.kind) {
|
||||
return `${hostname.value}${portString}`
|
||||
}
|
||||
throw Error(
|
||||
"Expecting to have a valid hostname kind." + JSON.stringify(hostname),
|
||||
)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { knownProtocols } from "../interfaces/Host"
|
||||
import { AddressInfo, Host, Hostname, HostnameInfo } from "../types"
|
||||
import { Effects } from "../Effects"
|
||||
import { DropGenerator, DropPromise } from "./Drop"
|
||||
import { IPV6_LINK_LOCAL } from "./ip"
|
||||
|
||||
export type UrlString = string
|
||||
export type HostId = string
|
||||
@@ -95,9 +96,9 @@ export const addressHostToUrl = (
|
||||
hostname = host.hostname.value
|
||||
} else if (host.kind === "ip") {
|
||||
if (host.hostname.kind === "domain") {
|
||||
hostname = `${host.hostname.subdomain ? `${host.hostname.subdomain}.` : ""}${host.hostname.domain}`
|
||||
hostname = host.hostname.value
|
||||
} else if (host.hostname.kind === "ipv6") {
|
||||
hostname = host.hostname.value.startsWith("fe80::")
|
||||
hostname = IPV6_LINK_LOCAL.contains(host.hostname.value)
|
||||
? `[${host.hostname.value}%${host.hostname.scopeId}]`
|
||||
: `[${host.hostname.value}]`
|
||||
} else {
|
||||
@@ -164,7 +165,7 @@ export const filledAddress = (
|
||||
addressInfo: AddressInfo,
|
||||
): FilledAddressInfo => {
|
||||
const toUrl = addressHostToUrl.bind(null, addressInfo)
|
||||
const hostnames = host.hostnameInfo[addressInfo.internalPort]
|
||||
const hostnames = host.hostnameInfo[addressInfo.internalPort] ?? []
|
||||
|
||||
return {
|
||||
...addressInfo,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/// Currently being used
|
||||
export { addressHostToUrl } from "./getServiceInterface"
|
||||
export { getDefaultString } from "./getDefaultString"
|
||||
export * from "./ip"
|
||||
|
||||
/// Not being used, but known to be browser compatible
|
||||
export { GetServiceInterface, getServiceInterface } from "./getServiceInterface"
|
||||
@@ -16,6 +17,5 @@ export { splitCommand } from "./splitCommand"
|
||||
export { nullIfEmpty } from "./nullIfEmpty"
|
||||
export { deepMerge, partialDiff } from "./deepMerge"
|
||||
export { deepEqual } from "./deepEqual"
|
||||
export { hostnameInfoToAddress } from "./Hostname"
|
||||
export * as regexes from "./regexes"
|
||||
export { stringFromStdErrOut } from "./stringFromStdErrOut"
|
||||
|
||||
85
sdk/base/lib/util/ip.ts
Normal file
85
sdk/base/lib/util/ip.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
export class IpAddress {
|
||||
readonly octets: number[]
|
||||
constructor(readonly address: string) {
|
||||
if (address.includes(":")) {
|
||||
this.octets = new Array(16).fill(0)
|
||||
const segs = address.split(":")
|
||||
let idx = 0
|
||||
let octIdx = 0
|
||||
while (segs[idx]) {
|
||||
const num = parseInt(segs[idx], 16)
|
||||
this.octets[octIdx++] = num >> 8
|
||||
this.octets[octIdx++] = num & 255
|
||||
idx += 1
|
||||
}
|
||||
const lastSegIdx = segs.length - 1
|
||||
if (idx < lastSegIdx) {
|
||||
idx = lastSegIdx
|
||||
octIdx = 15
|
||||
while (segs[idx]) {
|
||||
const num = parseInt(segs[idx], 16)
|
||||
this.octets[octIdx--] = num & 255
|
||||
this.octets[octIdx--] = num >> 8
|
||||
idx -= 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.octets = address.split(".").map(Number)
|
||||
if (this.octets.length !== 4) throw new Error("invalid ipv4 address")
|
||||
}
|
||||
if (this.octets.some((o) => o >= 256)) {
|
||||
throw new Error("invalid ip address")
|
||||
}
|
||||
}
|
||||
static parse(address: string): IpAddress {
|
||||
return new IpAddress(address)
|
||||
}
|
||||
isIpv4(): boolean {
|
||||
return this.octets.length === 4
|
||||
}
|
||||
isIpv6(): boolean {
|
||||
return this.octets.length === 16
|
||||
}
|
||||
isPublic(): boolean {
|
||||
return this.isIpv4() && !PRIVATE_IPV4_RANGES.some((r) => r.contains(this))
|
||||
}
|
||||
}
|
||||
|
||||
export class IpNet extends IpAddress {
|
||||
readonly prefix
|
||||
constructor(readonly ipnet: string) {
|
||||
const [address, prefixStr] = ipnet.split("/", 2)
|
||||
super(address)
|
||||
this.prefix = Number(prefixStr)
|
||||
}
|
||||
static parse(ipnet: string): IpNet {
|
||||
return new IpNet(ipnet)
|
||||
}
|
||||
contains(address: string | IpAddress): boolean {
|
||||
if (typeof address === "string") address = new IpAddress(address)
|
||||
if (this.octets.length !== address.octets.length) return false
|
||||
let prefix = this.prefix
|
||||
let idx = 0
|
||||
while (idx < this.octets.length && prefix >= 8) {
|
||||
if (this.octets[idx] !== address.octets[idx]) {
|
||||
return false
|
||||
}
|
||||
idx += 1
|
||||
prefix -= 8
|
||||
}
|
||||
if (prefix === 0 || idx >= this.octets.length) return true
|
||||
const mask = 255 << prefix
|
||||
return (this.octets[idx] & mask) === (address.octets[idx] & mask)
|
||||
}
|
||||
}
|
||||
|
||||
export const PRIVATE_IPV4_RANGES = [
|
||||
new IpNet("127.0.0.0/8"),
|
||||
new IpNet("10.0.0.0/8"),
|
||||
new IpNet("172.16.0.0/12"),
|
||||
new IpNet("192.168.0.0/16"),
|
||||
]
|
||||
|
||||
export const IPV6_LINK_LOCAL = new IpNet("fe80::/10")
|
||||
|
||||
export const CGNAT = new IpNet("100.64.0.0/10")
|
||||
@@ -61,7 +61,7 @@ import {
|
||||
} from "../../base/lib/inits"
|
||||
import { DropGenerator } from "../../base/lib/util/Drop"
|
||||
|
||||
export const OSVersion = testTypeVersion("0.4.0-alpha.9")
|
||||
export const OSVersion = testTypeVersion("0.4.0-alpha.10")
|
||||
|
||||
// prettier-ignore
|
||||
type AnyNeverCond<T extends any[], Then, Else> =
|
||||
@@ -104,7 +104,7 @@ export class StartSdk<Manifest extends T.SDKManifest> {
|
||||
|
||||
// prettier-ignore
|
||||
type StartSdkEffectWrapper = {
|
||||
[K in keyof Omit<Effects, NestedEffects | InterfaceEffects | MainUsedEffects | CallbackEffects | AlreadyExposed>]: (effects: Effects, ...args: Parameters<Effects[K]>) => ReturnType<Effects[K]>
|
||||
[K in keyof Omit<Effects, "eventId" | NestedEffects | InterfaceEffects | MainUsedEffects | CallbackEffects | AlreadyExposed>]: (effects: Effects, ...args: Parameters<Effects[K]>) => ReturnType<Effects[K]>
|
||||
}
|
||||
const startSdkEffectWrapper: StartSdkEffectWrapper = {
|
||||
restart: (effects, ...args) => effects.restart(...args),
|
||||
|
||||
@@ -197,7 +197,7 @@ async function runRsync(rsyncOptions: {
|
||||
for (const exclude of options.exclude) {
|
||||
args.push(`--exclude=${exclude}`)
|
||||
}
|
||||
args.push("-actAXH")
|
||||
args.push("-rlptgocAXH")
|
||||
args.push("--info=progress2")
|
||||
args.push("--no-inc-recursive")
|
||||
args.push(srcPath)
|
||||
|
||||
@@ -157,10 +157,14 @@ export class SubContainerOwned<
|
||||
) {
|
||||
super()
|
||||
this.leaderExited = false
|
||||
this.leader = cp.spawn("start-cli", ["subcontainer", "launch", rootfs], {
|
||||
killSignal: "SIGKILL",
|
||||
stdio: "inherit",
|
||||
})
|
||||
this.leader = cp.spawn(
|
||||
"start-container",
|
||||
["subcontainer", "launch", rootfs],
|
||||
{
|
||||
killSignal: "SIGKILL",
|
||||
stdio: "inherit",
|
||||
},
|
||||
)
|
||||
this.leader.on("exit", () => {
|
||||
this.leaderExited = true
|
||||
})
|
||||
@@ -407,7 +411,7 @@ export class SubContainerOwned<
|
||||
delete options.cwd
|
||||
}
|
||||
const child = cp.spawn(
|
||||
"start-cli",
|
||||
"start-container",
|
||||
[
|
||||
"subcontainer",
|
||||
"exec",
|
||||
@@ -529,7 +533,7 @@ export class SubContainerOwned<
|
||||
await this.killLeader()
|
||||
this.leaderExited = false
|
||||
this.leader = cp.spawn(
|
||||
"start-cli",
|
||||
"start-container",
|
||||
[
|
||||
"subcontainer",
|
||||
"launch",
|
||||
@@ -571,7 +575,7 @@ export class SubContainerOwned<
|
||||
delete options.cwd
|
||||
}
|
||||
return cp.spawn(
|
||||
"start-cli",
|
||||
"start-container",
|
||||
[
|
||||
"subcontainer",
|
||||
"exec",
|
||||
|
||||
@@ -269,7 +269,7 @@ export class FileHelper<A> {
|
||||
eq: (left: B | null | undefined, right: B | null) => boolean,
|
||||
abort?: AbortSignal,
|
||||
) {
|
||||
let res
|
||||
let prev: { value: B | null } | null = null
|
||||
while (effects.isInContext && !abort?.aborted) {
|
||||
if (await exists(this.path)) {
|
||||
const ctrl = new AbortController()
|
||||
@@ -287,8 +287,10 @@ export class FileHelper<A> {
|
||||
}
|
||||
})
|
||||
.catch((e) => console.error(asError(e)))
|
||||
if (!eq(res, newRes)) yield newRes
|
||||
res = newRes
|
||||
if (!prev || !eq(prev.value, newRes)) {
|
||||
yield newRes
|
||||
}
|
||||
prev = { value: newRes }
|
||||
await listen
|
||||
} else {
|
||||
yield null
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from "../../../base/lib/util"
|
||||
export { GetSslCertificate } from "./GetSslCertificate"
|
||||
|
||||
export { hostnameInfoToAddress } from "../../../base/lib/util/Hostname"
|
||||
export { Drop } from "../../../base/lib/util/Drop"
|
||||
|
||||
4
sdk/package/package-lock.json
generated
4
sdk/package/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.36",
|
||||
"version": "0.4.0-beta.37",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.36",
|
||||
"version": "0.4.0-beta.37",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.36",
|
||||
"version": "0.4.0-beta.37",
|
||||
"description": "Software development kit to facilitate packaging services for StartOS",
|
||||
"main": "./package/lib/index.js",
|
||||
"types": "./package/lib/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user