add some comments, bump to rc4

This commit is contained in:
Matt Hill
2023-05-03 16:09:32 -06:00
parent 9a1dd5a399
commit 0ddd35c8d7
14 changed files with 127 additions and 43 deletions

View File

@@ -1,5 +1,4 @@
import { DeepPartial, Dependencies, Effects, ExpectedExports } from "../types" import { Effects, ExpectedExports } from "../types"
import { InputSpec } from "./configTypes"
import { SDKManifest } from "../manifest/ManifestTypes" import { SDKManifest } from "../manifest/ManifestTypes"
import * as D from "./dependencies" import * as D from "./dependencies"
import { Config, ExtractConfigType } from "./builder/config" import { Config, ExtractConfigType } from "./builder/config"

View File

@@ -1,6 +1,5 @@
import { ManifestVersion } from "../../manifest/ManifestTypes" import { ManifestVersion } from "../../manifest/ManifestTypes"
import { Effects } from "../../types" import { Effects } from "../../types"
import { Utils } from "../../util"
export class Migration<Version extends ManifestVersion> { export class Migration<Version extends ManifestVersion> {
constructor( constructor(

View File

@@ -19,27 +19,26 @@ type Daemon<Ids extends string, Command extends string, Id extends string> = {
type ErrorDuplicateId<Id extends string> = `The id '${Id}' is already used` type ErrorDuplicateId<Id extends string> = `The id '${Id}' is already used`
/** /**
* Used during the main of a function, it allows us to describe and ensure a set of daemons are running. * A class for defining and controlling the service daemons
* With the dependency, we are using this like an init system, where we can ensure that a daemon is running
* The return type of this is used in the runningMain
```ts ```ts
Daemons.with({ Daemons.of({
effects, effects,
started, started,
interfacesReceipt, interfaceReceipt, // Provide the interfaceReceipt to prove it was completed
}) healthReceipts, // Provide the healthReceipts or [] to prove they were at least considered
.addDaemon({ }).addDaemon('webui', {
id: "nostr", command: 'hello-world', // The command to start the daemon
command: "./nostr-rs-relay --db /data", ready: {
ready: { display: 'Web Interface',
display: { // The function to run to determine the health status of the daemon
name: "Websocket Live", fn: () =>
message: "The websocket is live", checkPortListening(effects, 80, {
}, successMessage: 'The web interface is ready',
fn: () => checkPortListening(effects, 8080), errorMessage: 'The web interface is not ready',
}, }),
}) },
.build() requires: [],
})
``` ```
*/ */
export class Daemons<Ids extends string> { export class Daemons<Ids extends string> {
@@ -48,7 +47,16 @@ export class Daemons<Ids extends string> {
readonly started: (onTerm: () => void) => null, readonly started: (onTerm: () => void) => null,
readonly daemons?: Daemon<Ids, "command", Ids>[], readonly daemons?: Daemon<Ids, "command", Ids>[],
) {} ) {}
/**
* Returns an empty new Daemons class with the provided config.
*
* Call .addDaemon() on the returned class to add a daemon.
*
* Daemons run in the order they are defined, with latter daemons being capable of
* depending on prior daemons
* @param config
* @returns
*/
static of(config: { static of(config: {
effects: Effects effects: Effects
started: (onTerm: () => void) => null started: (onTerm: () => void) => null
@@ -57,6 +65,12 @@ export class Daemons<Ids extends string> {
}) { }) {
return new Daemons<never>(config.effects, config.started) return new Daemons<never>(config.effects, config.started)
} }
/**
* Returns the complete list of daemons, including the one defined here
* @param id
* @param newDaemon
* @returns
*/
addDaemon<Id extends string, Command extends string>( addDaemon<Id extends string, Command extends string>(
// prettier-ignore // prettier-ignore
id: id:

View File

@@ -1,5 +1,4 @@
import { Effects } from "../types" import { Effects } from "../types"
import { LocalPort } from "./LocalPort"
import { TorHostname } from "./TorHostname" import { TorHostname } from "./TorHostname"
export class NetworkBuilder { export class NetworkBuilder {

View File

@@ -2,6 +2,17 @@ import { Effects } from "../types"
import { AddressReceipt } from "./AddressReceipt" import { AddressReceipt } from "./AddressReceipt"
import { Origin } from "./Origin" import { Origin } from "./Origin"
/**
* A helper class for creating a Network Interface
*
* Network Interfaces are collections of web addresses that expose the same API or other resource,
* display to the user with under a common name and description.
*
* All URIs on an interface inherit the same ui: bool, basic auth credentials, path, and search (query) params
*
* @param options
* @returns
*/
export class NetworkInterfaceBuilder { export class NetworkInterfaceBuilder {
constructor( constructor(
readonly options: { readonly options: {
@@ -16,6 +27,14 @@ export class NetworkInterfaceBuilder {
}, },
) {} ) {}
/**
* A function to register a group of origins (<PROTOCOL> :// <HOSTNAME> : <PORT>) with StartOS
*
* The returned addressReceipt serves as proof that the addresses were registered
*
* @param addresses
* @returns
*/
async exportAddresses(addresses: Iterable<Origin>) { async exportAddresses(addresses: Iterable<Origin>) {
const { name, description, id, ui, path, search } = this.options const { name, description, id, ui, path, search } = this.options
for (const origin of addresses) { for (const origin of addresses) {

View File

@@ -1,6 +1,11 @@
import { AddressReceipt } from "./AddressReceipt" import { AddressReceipt } from "./AddressReceipt"
import { InterfaceReceipt } from "./interfaceReceipt" import { InterfaceReceipt } from "./interfaceReceipt"
/**
* Takes a list of addressReceipts
*
* Returns an interfaceReceipt, which is needed to create the service daemons
*/
export const exportInterfaces = ( export const exportInterfaces = (
_firstProof: AddressReceipt, _firstProof: AddressReceipt,
..._rest: AddressReceipt[] ..._rest: AddressReceipt[]

View File

@@ -19,7 +19,10 @@ export interface SDKManifest {
id: string id: string
/** A human readable service title */ /** A human readable service title */
title: string title: string
/** Service version - accepts up to four digits, where the last confirms to revisions necessary for StartOs - see documentation: https://github.com/Start9Labs/emver-rs. This value will change with each release of the service */ /** Service version - accepts up to four digits, where the last confirms to revisions necessary for StartOs
* - see documentation: https://github.com/Start9Labs/emver-rs. This value will change with each release of
* the service
*/
version: ManifestVersion version: ManifestVersion
/** Release notes for the update - can be a string, paragraph or URL */ /** Release notes for the update - can be a string, paragraph or URL */
releaseNotes: string releaseNotes: string
@@ -27,7 +30,10 @@ export interface SDKManifest {
license: string // name of license license: string // name of license
/** A list of normie (hosted, SaaS, custodial, etc) services this services intends to replace */ /** A list of normie (hosted, SaaS, custodial, etc) services this services intends to replace */
replaces: string[] replaces: string[]
/** The Start9 wrapper repository URL for the package. This repo contains the manifest file (this), any scripts necessary for configuration, backups, actions, or health checks (more below). This key must exist. But could be embedded into the source repository */ /** The Start9 wrapper repository URL for the package. This repo contains the manifest file (this),
* any scripts necessary for configuration, backups, actions, or health checks (more below). This key
* must exist. But could be embedded into the source repository
*/
wrapperRepo: string wrapperRepo: string
/** The original project repository URL. There is no upstream repo in this example */ /** The original project repository URL. There is no upstream repo in this example */
upstreamRepo: string upstreamRepo: string
@@ -44,15 +50,18 @@ export interface SDKManifest {
/** This description will display with additional details in the service's individual marketplace page */ /** This description will display with additional details in the service's individual marketplace page */
long: string long: string
} }
/** These assets are static files necessary for packaging the service for Start9 (into an s9pk). Each value is a path to the specified asset. If an asset is missing from this list, or otherwise denoted, it will be defaulted to the values denoted below. */ /** These assets are static files necessary for packaging the service for Start9 (into an s9pk).
* Each value is a path to the specified asset. If an asset is missing from this list, or otherwise
* denoted, it will be defaulted to the values denoted below.
*/
assets: { assets: {
icon: string // file path icon: string // file path
instructions: string // file path instructions: string // file path
license: string // file path license: string // file path
} }
/**Defines the containers needed to run the main and mounted volumes */ /** Defines the containers needed to run the main and mounted volumes */
containers: Record<string, Container> containers: Record<string, Container>
/**This denotes any data, asset, or pointer volumes that should be connected when the "docker run" command is invoked */ /** This denotes any data, asset, or pointer volumes that should be connected when the "docker run" command is invoked */
volumes: Record<string, string> volumes: Record<string, string>
actions: Array<ActionMetaData> actions: Array<ActionMetaData>
alerts: { alerts: {
@@ -68,7 +77,8 @@ export interface SDKManifest {
export interface Dependency { export interface Dependency {
/** The range of versions that would satisfy the dependency /** The range of versions that would satisfy the dependency
* ie: >=3.4.5 && <4.0.0 *
* ie: >=3.4.5 <4.0.0
*/ */
version: string version: string
/** /**

View File

@@ -2,8 +2,16 @@ import { PackagePropertyGroup } from "../types"
import { PropertyPage } from "./PropertyPage" import { PropertyPage } from "./PropertyPage"
import { PropertyString } from "./PropertyString" import { PropertyString } from "./PropertyString"
/**
* A Property Group is a list of values, separated from other property groups by a whitespace divider with an optional header
*/
export class PropertyGroup { export class PropertyGroup {
private constructor(readonly data: PackagePropertyGroup) {} private constructor(readonly data: PackagePropertyGroup) {}
/**
* Returns a new Property Group with the provided options
* @param options
* @returns
*/
static of(options: { static of(options: {
header: string | null header: string | null
values: (PropertyPage | PropertyString)[] values: (PropertyPage | PropertyString)[]

View File

@@ -1,8 +1,18 @@
import { PackagePropertyPage } from "../types" import { PackagePropertyPage } from "../types"
import { PropertyGroup } from "./PropertyGroup" import { PropertyGroup } from "./PropertyGroup"
/**
* A Property Page will display to the user as a button with a name a description.
* Clicking the button will take the user to a nested page displaying the provided
* list of Property Groups
*/
export class PropertyPage { export class PropertyPage {
private constructor(readonly data: PackagePropertyPage) {} private constructor(readonly data: PackagePropertyPage) {}
/**
* Returns a new Property Page with the provided options
* @param options
* @returns
*/
static of(options: { static of(options: {
name: string name: string
description: string | null description: string | null

View File

@@ -1,8 +1,16 @@
import { PackagePropertyString } from "../types" import { PackagePropertyString } from "../types"
/**
* A Property String is an arbitrary string value to display to the user
*/
export class PropertyString { export class PropertyString {
private constructor(readonly data: PackagePropertyString) {} private constructor(readonly data: PackagePropertyString) {}
static of(value: Omit<PackagePropertyString, "type" | "watch">) { /**
* Returns a new Property String with the provided options
* @param value
* @returns
*/
static of(value: Omit<PackagePropertyString, "type">) {
return new PropertyString({ return new PropertyString({
...value, ...value,
type: "string", type: "string",

View File

@@ -3,8 +3,8 @@ import { Effects } from "../types"
export class GetSystemSmtp { export class GetSystemSmtp {
constructor(readonly effects: Effects) {} constructor(readonly effects: Effects) {}
/** This should be used as the primary method in main since it allows the main to /**
* restart if the wrapper data changes * Returns the system SMTP credentials. Restarts the service if the credentials change
*/ */
const() { const() {
return this.effects.getSystemSmtp({ return this.effects.getSystemSmtp({
@@ -12,8 +12,7 @@ export class GetSystemSmtp {
}) })
} }
/** /**
* Returns the wrapper data once and then never again * Returns the system SMTP credentials. Does nothing if the credentials change
* Doesn't restart the server when the wrapper data changes
*/ */
once() { once() {
return this.effects.getSystemSmtp({ return this.effects.getSystemSmtp({
@@ -21,7 +20,7 @@ export class GetSystemSmtp {
}) })
} }
/** /**
* Keeps giving the latest wrapper data as it changes * Watches the system SMTP credentials. Takes a custom callback function to run whenever the credentials change
*/ */
async *watch() { async *watch() {
while (true) { while (true) {

View File

@@ -89,6 +89,11 @@ export class FileHelper<A> {
}), }),
) )
} }
/**
* Create a File Helper for an arbitrary file type.
*
* Provide custom functions for translating data to the file format and visa versa.
*/
static raw<A>( static raw<A>(
path: string, path: string,
volume: string, volume: string,
@@ -97,6 +102,9 @@ export class FileHelper<A> {
) { ) {
return new FileHelper<A>(path, volume, toFile, fromFile) return new FileHelper<A>(path, volume, toFile, fromFile)
} }
/**
* Create a File Helper for a .json file
*/
static json<A>( static json<A>(
path: string, path: string,
volume: string, volume: string,
@@ -113,6 +121,9 @@ export class FileHelper<A> {
}, },
) )
} }
/**
* Create a File Helper for a .toml file
*/
static toml<A extends Record<string, unknown>>( static toml<A extends Record<string, unknown>>(
path: string, path: string,
volume: string, volume: string,
@@ -129,6 +140,9 @@ export class FileHelper<A> {
}, },
) )
} }
/**
* Create a File Helper for a .yaml file
*/
static yaml<A extends Record<string, unknown>>( static yaml<A extends Record<string, unknown>>(
path: string, path: string,
volume: string, volume: string,

View File

@@ -12,8 +12,8 @@ export class GetWrapperData<WrapperData, Path extends string> {
} = {}, } = {},
) {} ) {}
/** This should be used as the primary method in main since it allows the main to /**
* restart if the wrapper data changes * Returns the value of WrapperData at the provided path. Restart the service if the value changes
*/ */
const() { const() {
return this.effects.getWrapperData<WrapperData, Path>({ return this.effects.getWrapperData<WrapperData, Path>({
@@ -23,8 +23,7 @@ export class GetWrapperData<WrapperData, Path extends string> {
}) })
} }
/** /**
* Returns the wrapper data once and then never again * Returns the value of WrapperData at the provided path. Does nothing if the value changes
* Doesn't restart the server when the wrapper data changes
*/ */
once() { once() {
return this.effects.getWrapperData<WrapperData, Path>({ return this.effects.getWrapperData<WrapperData, Path>({
@@ -33,8 +32,9 @@ export class GetWrapperData<WrapperData, Path extends string> {
callback: () => {}, callback: () => {},
}) })
} }
/** /**
* Keeps giving the latest wrapper data as it changes * Watches the value of WrapperData at the provided path. Takes a custom callback function to run whenever the value changes
*/ */
async *watch() { async *watch() {
while (true) { while (true) {

View File

@@ -1,6 +1,6 @@
{ {
"name": "start-sdk", "name": "start-sdk",
"version": "0.4.0-lib0.rc3", "version": "0.4.0-lib0.rc4",
"description": "For making the patterns that are wanted in making services for the startOS.", "description": "For making the patterns that are wanted in making services for the startOS.",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",