Merge pull request #11 from Start9Labs/feat/more-iface

add hasPrimary and disabled to network interfaces
This commit is contained in:
Matt Hill
2023-05-31 15:24:31 -06:00
committed by GitHub
10 changed files with 120 additions and 34 deletions

View File

@@ -41,12 +41,6 @@ export const customSmtp = Config.of<ConfigSpecOf<SmtpValue>, never>({
required: false, required: false,
masked: true, masked: true,
}), }),
tls: Value.toggle({
name: "Require Transport Security",
default: true,
description:
"Require TLS transport security. If disabled, email will use plaintext by default and TLS via STARTTLS <strong>if the SMTP server supports it</strong>. If enabled, email will refuse to connect unless the server supports STARTTLS.",
}),
}) })
/** /**

View File

@@ -21,6 +21,8 @@ export class NetworkInterfaceBuilder {
name: string name: string
id: string id: string
description: string description: string
hasPrimary: boolean
disabled: boolean
ui: boolean ui: boolean
username: null | string username: null | string
path: string path: string
@@ -39,7 +41,17 @@ export class NetworkInterfaceBuilder {
async export<Origins extends Origin<Host>[]>( async export<Origins extends Origin<Host>[]>(
origins: Origins, origins: Origins,
): Promise<Address[] & AddressReceipt> { ): Promise<Address[] & AddressReceipt> {
const { name, description, id, ui, username, path, search } = this.options const {
name,
description,
hasPrimary,
disabled,
id,
ui,
username,
path,
search,
} = this.options
const addresses = Array.from(origins).map((o) => const addresses = Array.from(origins).map((o) =>
o.build({ username, path, search, scheme: null }), o.build({ username, path, search, scheme: null }),
@@ -49,6 +61,8 @@ export class NetworkInterfaceBuilder {
interfaceId: id, interfaceId: id,
name, name,
description, description,
hasPrimary,
disabled,
addresses, addresses,
ui, ui,
}) })

View File

@@ -1,8 +1,6 @@
import { MultiHost } from "../interfaces/Host"
import { NetworkInterfaceBuilder } from "../interfaces/NetworkInterfaceBuilder" import { NetworkInterfaceBuilder } from "../interfaces/NetworkInterfaceBuilder"
import { Effects } from "../types" import { Effects } from "../types"
import { createUtils } from "../util" import { createUtils } from "../util"
import { sdk } from "./output.sdk"
describe("host", () => { describe("host", () => {
test("Testing that the types work", () => { test("Testing that the types work", () => {
@@ -15,6 +13,8 @@ describe("host", () => {
name: "Foo", name: "Foo",
id: "foo", id: "foo",
description: "A Foo", description: "A Foo",
hasPrimary: false,
disabled: false,
ui: true, ui: true,
username: "bar", username: "bar",
path: "/baz", path: "/baz",

View File

@@ -0,0 +1,20 @@
import { getHostname } from "../util/getNetworkInterface"
describe("getHostname ", () => {
const inputToExpected = [
["http://localhost:3000", "localhost"],
["http://localhost", "localhost"],
["localhost", "localhost"],
["http://127.0.0.1/", "127.0.0.1"],
["http://127.0.0.1/testing/1234?314345", "127.0.0.1"],
["127.0.0.1/", "127.0.0.1"],
["http://mail.google.com/", "mail.google.com"],
["mail.google.com/", "mail.google.com"],
]
for (const [input, expectValue] of inputToExpected) {
test(`should return ${expectValue} for ${input}`, () => {
expect(getHostname(input)).toEqual(expectValue)
})
}
})

View File

@@ -2,6 +2,7 @@ export * as configTypes from "./config/configTypes"
import { InputSpec } from "./config/configTypes" import { InputSpec } from "./config/configTypes"
import { DependenciesReceipt } from "./config/setupConfig" import { DependenciesReceipt } from "./config/setupConfig"
import { PortOptions } from "./interfaces/Host" import { PortOptions } from "./interfaces/Host"
import { UrlString } from "./util/getNetworkInterface"
export type ExportedAction = (options: { export type ExportedAction = (options: {
effects: Effects effects: Effects
@@ -143,7 +144,6 @@ export type SmtpValue = {
from: string from: string
login: string login: string
password: string | null | undefined password: string | null | undefined
tls: boolean
} }
export type CommandType<A extends string> = export type CommandType<A extends string> =
@@ -185,12 +185,16 @@ export type NetworkInterface = {
name: string name: string
/** Human readable description, used as tooltip usually */ /** Human readable description, used as tooltip usually */
description: string description: string
/** Whether or not one address must be the primary address */
hasPrimary: boolean
/** Disabled interfaces do not serve, but they retain their metadata and addresses */
disabled: boolean
/** All URIs */ /** All URIs */
addresses: Address[] addresses: Address[]
/** Defaults to false, but describes if this address can be opened in a browser as an /** Defaults to false, but describes if this address can be opened in a browser as an
* ui interface * ui interface
*/ */
ui?: boolean ui: boolean
} }
// prettier-ignore // prettier-ignore
export type ExposeAllServicePaths<Store, PreviousPath extends string = ""> = export type ExposeAllServicePaths<Store, PreviousPath extends string = ""> =
@@ -370,6 +374,16 @@ export type Effects = {
callback: () => void callback: () => void
}): Promise<NetworkInterface> }): Promise<NetworkInterface>
/**
* The user sets the primary url for a interface
* @param options
*/
getPrimaryUrl(options: {
packageId?: PackageId
interfaceId: InterfaceId
callback: () => void
}): Promise<UrlString | null>
/** /**
* There are times that we want to see the addresses that where exported * There are times that we want to see the addresses that where exported
* @param options.addressId If we want to filter the address id * @param options.addressId If we want to filter the address id

View File

@@ -4,6 +4,16 @@ import * as regexes from "./regexes"
export type UrlString = string export type UrlString = string
export type HostId = string export type HostId = string
const getHostnameRegex = /^(\w+:\/\/)?([^\/\:]+)(:\d{1,3})?(\/)?/
export const getHostname = (url: string): HostName | null => {
const founds = url.match(getHostnameRegex)?.[2]
if (!founds) return null
const parts = founds.split("@")
const last = parts[parts.length - 1] as HostName | null
console.log({ url, parts, founds, last })
return last
}
export type Filled = { export type Filled = {
hostnames: HostName[] hostnames: HostName[]
onionHostnames: HostName[] onionHostnames: HostName[]
@@ -30,12 +40,19 @@ export type NetworkInterfaceFilled = {
name: string name: string
/** Human readable description, used as tooltip usually */ /** Human readable description, used as tooltip usually */
description: string description: string
/** Whether or not the interface has a primary URL */
hasPrimary: boolean
/** Whether or not the interface disabled */
disabled: boolean
/** All URIs */ /** All URIs */
addresses: FilledAddress[] addresses: FilledAddress[]
/** Defaults to false, but describes if this address can be opened in a browser as an /** Defaults to false, but describes if this address can be opened in a browser as an
* ui interface * ui interface
*/ */
ui?: boolean ui: boolean
primaryHostname: HostName | null
primaryUrl: UrlString | null
} & Filled } & Filled
const either = const either =
<A>(...args: ((a: A) => boolean)[]) => <A>(...args: ((a: A) => boolean)[]) =>
@@ -118,6 +135,7 @@ export const filledAddress = (
export const networkInterfaceFilled = ( export const networkInterfaceFilled = (
interfaceValue: NetworkInterface, interfaceValue: NetworkInterface,
primaryUrl: UrlString | null,
addresses: FilledAddress[], addresses: FilledAddress[],
): NetworkInterfaceFilled => { ): NetworkInterfaceFilled => {
return { return {
@@ -147,6 +165,10 @@ export const networkInterfaceFilled = (
get allHostnames() { get allHostnames() {
return unique(addresses.flatMap((x) => x.allHostnames)) return unique(addresses.flatMap((x) => x.allHostnames))
}, },
get primaryHostname() {
if (primaryUrl == null) return null
return getHostname(primaryUrl)
},
get urls() { get urls() {
return unique(addresses.flatMap((x) => x.urls)) return unique(addresses.flatMap((x) => x.urls))
}, },
@@ -171,6 +193,7 @@ export const networkInterfaceFilled = (
get allUrls() { get allUrls() {
return unique(addresses.flatMap((x) => x.allUrls)) return unique(addresses.flatMap((x) => x.allUrls))
}, },
primaryUrl,
} }
} }
const makeInterfaceFilled = async ({ const makeInterfaceFilled = async ({
@@ -189,24 +212,32 @@ const makeInterfaceFilled = async ({
packageId, packageId,
callback, callback,
}) })
const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries( const hostIdsRecord = Promise.all(
await Promise.all( unique(interfaceValue.addresses.map((x) => x.hostId)).map(
unique(interfaceValue.addresses.map((x) => x.hostId)).map( async (hostId) =>
async (hostId) => [ [
hostId, hostId,
effects.getHostnames({ await effects.getHostnames({
packageId, packageId,
hostId, hostId,
callback, callback,
}), }),
], ] as const,
),
), ),
) )
const primaryUrl = effects.getPrimaryUrl({
interfaceId,
packageId,
callback,
})
const fillAddress = filledAddress.bind(null, hostIdsRecord) const fillAddress = filledAddress.bind(
null,
Object.fromEntries(await hostIdsRecord),
)
const interfaceFilled: NetworkInterfaceFilled = networkInterfaceFilled( const interfaceFilled: NetworkInterfaceFilled = networkInterfaceFilled(
interfaceValue, interfaceValue,
await primaryUrl,
interfaceValue.addresses.map(fillAddress), interfaceValue.addresses.map(fillAddress),
) )
return interfaceFilled return interfaceFilled

View File

@@ -19,30 +19,39 @@ const makeManyInterfaceFilled = async ({
packageId, packageId,
callback, callback,
}) })
const hostIdsRecord: { [hostId: HostId]: HostName[] } = Object.fromEntries( const hostIdsRecord = Object.fromEntries(
await Promise.all( await Promise.all(
Array.from( Array.from(
new Set( new Set(
interfaceValues.flatMap((x) => x.addresses).map((x) => x.hostId), interfaceValues.flatMap((x) => x.addresses).map((x) => x.hostId),
), ),
).map(async (hostId) => [ ).map(
hostId, async (hostId) =>
effects.getHostnames({ [
packageId, hostId,
hostId, await effects.getHostnames({
callback, packageId,
}), hostId,
]), callback,
}),
] as const,
),
), ),
) )
const fillAddress = filledAddress.bind(null, hostIdsRecord) const fillAddress = filledAddress.bind(null, hostIdsRecord)
const interfacesFilled: NetworkInterfaceFilled[] = interfaceValues.map( const interfacesFilled: NetworkInterfaceFilled[] = await Promise.all(
(interfaceValue) => interfaceValues.map(async (interfaceValue) =>
networkInterfaceFilled( networkInterfaceFilled(
interfaceValue, interfaceValue,
await effects.getPrimaryUrl({
interfaceId: interfaceValue.interfaceId,
packageId,
callback,
}),
interfaceValue.addresses.map(fillAddress), interfaceValue.addresses.map(fillAddress),
), ),
),
) )
return interfacesFilled return interfacesFilled
} }

View File

@@ -56,6 +56,8 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
name: string name: string
id: string id: string
description: string description: string
hasPrimary: boolean
disabled: boolean
ui: boolean ui: boolean
username: null | string username: null | string
path: string path: string
@@ -114,6 +116,8 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
name: string name: string
id: string id: string
description: string description: string
hasPrimary: boolean
disabled: boolean
ui: boolean ui: boolean
username: null | string username: null | string
path: string path: string

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "@start9labs/start-sdk", "name": "@start9labs/start-sdk",
"version": "0.4.0-rev0.lib0.rc4", "version": "0.4.0-rev0.lib0.rc5",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@start9labs/start-sdk", "name": "@start9labs/start-sdk",
"version": "0.4.0-rev0.lib0.rc4", "version": "0.4.0-rev0.lib0.rc5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@start9labs/start-sdk", "name": "@start9labs/start-sdk",
"version": "0.4.0-rev0.lib0.rc4", "version": "0.4.0-rev0.lib0.rc5",
"description": "Software development kit to facilitate packaging services for StartOS", "description": "Software development kit to facilitate packaging services for StartOS",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",