mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-31 04:33:40 +00:00
Merge pull request #11 from Start9Labs/feat/more-iface
add hasPrimary and disabled to network interfaces
This commit is contained in:
@@ -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.",
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
20
lib/test/util.getNetworkInterface.test.ts
Normal file
20
lib/test/util.getNetworkInterface.test.ts
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
18
lib/types.ts
18
lib/types.ts
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
4
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user