mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-31 04:33:40 +00:00
feat: Add in some helpers for the properties
This commit is contained in:
@@ -11,3 +11,4 @@ export * as TOML from "@iarna/toml";
|
|||||||
export * as Types from "./types";
|
export * as Types from "./types";
|
||||||
export * as util from "./util";
|
export * as util from "./util";
|
||||||
export * as YAML from "yaml";
|
export * as YAML from "yaml";
|
||||||
|
export * as properties from "./properties";
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ import { Trigger } from "../health/trigger";
|
|||||||
import { defaultTrigger } from "../health/trigger/defaultTrigger";
|
import { defaultTrigger } from "../health/trigger/defaultTrigger";
|
||||||
import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types";
|
import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types";
|
||||||
import { InterfaceReceipt } from "./interfaceReceipt";
|
import { InterfaceReceipt } from "./interfaceReceipt";
|
||||||
type Daemon<Ids extends string | never, Command extends string, Id extends string> = {
|
type Daemon<
|
||||||
|
Ids extends string | never,
|
||||||
|
Command extends string,
|
||||||
|
Id extends string
|
||||||
|
> = {
|
||||||
id: Id;
|
id: Id;
|
||||||
command: ValidIfNoStupidEscape<Command> | [string, ...string[]];
|
command: ValidIfNoStupidEscape<Command> | [string, ...string[]];
|
||||||
|
|
||||||
@@ -59,7 +63,9 @@ export class Daemons<Ids extends string | never> {
|
|||||||
}) {
|
}) {
|
||||||
return new Daemons<never>(config.effects, config.started);
|
return new Daemons<never>(config.effects, config.started);
|
||||||
}
|
}
|
||||||
addDaemon<Id extends string, Command extends string>(newDaemon: Daemon<Ids, Command, Id>) {
|
addDaemon<Id extends string, Command extends string>(
|
||||||
|
newDaemon: Daemon<Ids, Command, Id>
|
||||||
|
) {
|
||||||
const daemons = ((this?.daemons ?? []) as any[]).concat(newDaemon);
|
const daemons = ((this?.daemons ?? []) as any[]).concat(newDaemon);
|
||||||
return new Daemons<Ids | Id>(this.effects, this.started, daemons);
|
return new Daemons<Ids | Id>(this.effects, this.started, daemons);
|
||||||
}
|
}
|
||||||
@@ -70,13 +76,19 @@ export class Daemons<Ids extends string | never> {
|
|||||||
const daemons = this.daemons ?? [];
|
const daemons = this.daemons ?? [];
|
||||||
const _config = await effects.getServiceConfig();
|
const _config = await effects.getServiceConfig();
|
||||||
for (const daemon of daemons) {
|
for (const daemon of daemons) {
|
||||||
const requiredPromise = Promise.all(daemon.requires?.map((id) => daemonsStarted[id]) ?? []);
|
const requiredPromise = Promise.all(
|
||||||
|
daemon.requires?.map((id) => daemonsStarted[id]) ?? []
|
||||||
|
);
|
||||||
daemonsStarted[daemon.id] = requiredPromise.then(async () => {
|
daemonsStarted[daemon.id] = requiredPromise.then(async () => {
|
||||||
const { command } = daemon;
|
const { command } = daemon;
|
||||||
|
|
||||||
const child = effects.runDaemon(command);
|
const child = effects.runDaemon(command);
|
||||||
const trigger = (daemon.ready.trigger ?? defaultTrigger)();
|
const trigger = (daemon.ready.trigger ?? defaultTrigger)();
|
||||||
for (let res = await trigger.next({}); !res.done; res = await trigger.next({})) {
|
for (
|
||||||
|
let res = await trigger.next({});
|
||||||
|
!res.done;
|
||||||
|
res = await trigger.next({})
|
||||||
|
) {
|
||||||
const response = await daemon.ready.fn();
|
const response = await daemon.ready.fn();
|
||||||
if (response.status === "passing") {
|
if (response.status === "passing") {
|
||||||
return child;
|
return child;
|
||||||
@@ -87,10 +99,18 @@ export class Daemons<Ids extends string | never> {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
async term() {
|
async term() {
|
||||||
await Promise.all(Object.values<Promise<DaemonReturned>>(daemonsStarted).map((x) => x.then((x) => x.term())));
|
await Promise.all(
|
||||||
|
Object.values<Promise<DaemonReturned>>(daemonsStarted).map((x) =>
|
||||||
|
x.then((x) => x.term())
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
async wait() {
|
async wait() {
|
||||||
await Promise.all(Object.values<Promise<DaemonReturned>>(daemonsStarted).map((x) => x.then((x) => x.wait())));
|
await Promise.all(
|
||||||
|
Object.values<Promise<DaemonReturned>>(daemonsStarted).map((x) =>
|
||||||
|
x.then((x) => x.wait())
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ export { Daemons } from "./Daemons";
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const runningMain: (
|
export const runningMain: (
|
||||||
fn: (o: { effects: Effects; started(onTerm: () => void): null }) => Promise<Daemons<any>>
|
fn: (o: {
|
||||||
|
effects: Effects;
|
||||||
|
started(onTerm: () => void): null;
|
||||||
|
}) => Promise<Daemons<any>>
|
||||||
) => ExpectedExports.main = (fn) => {
|
) => ExpectedExports.main = (fn) => {
|
||||||
return async (options) => {
|
return async (options) => {
|
||||||
const result = await fn(options);
|
const result = await fn(options);
|
||||||
|
|||||||
36
lib/properties/Properties.ts
Normal file
36
lib/properties/Properties.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import {
|
||||||
|
PackagePropertiesV2,
|
||||||
|
PackagePropertyObject,
|
||||||
|
PackagePropertyString,
|
||||||
|
Properties as P,
|
||||||
|
} from "../types";
|
||||||
|
import { PropertyObject } from "./PropertyObject";
|
||||||
|
import { PropertyString } from "./PropertyString";
|
||||||
|
|
||||||
|
export class Properties<X extends PackagePropertiesV2> {
|
||||||
|
constructor(readonly data: X) {}
|
||||||
|
|
||||||
|
static of<
|
||||||
|
X extends Record<
|
||||||
|
string,
|
||||||
|
| PropertyObject<PackagePropertyObject>
|
||||||
|
| PropertyString<PackagePropertyString>
|
||||||
|
>
|
||||||
|
>(x: X) {
|
||||||
|
const answer = {} as {
|
||||||
|
[key in keyof X]: X[key]["data"];
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [key, value] of x.entries()) {
|
||||||
|
answer[key] = value.data;
|
||||||
|
}
|
||||||
|
return new Properties(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
return {
|
||||||
|
version: 2,
|
||||||
|
data: this.data,
|
||||||
|
} satisfies P;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
lib/properties/PropertyObject.ts
Normal file
16
lib/properties/PropertyObject.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { PackagePropertiesV2, PackagePropertyObject } from "../types";
|
||||||
|
import { Properties } from "./Properties";
|
||||||
|
|
||||||
|
export class PropertyObject<X extends PackagePropertyObject> {
|
||||||
|
private constructor(readonly data: X) {}
|
||||||
|
static of<X extends Properties<PackagePropertiesV2>>(
|
||||||
|
description: string,
|
||||||
|
value: X
|
||||||
|
) {
|
||||||
|
return new PropertyObject({
|
||||||
|
type: "object",
|
||||||
|
description,
|
||||||
|
value: value.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
20
lib/properties/PropertyString.ts
Normal file
20
lib/properties/PropertyString.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { PackagePropertyString } from "../types";
|
||||||
|
|
||||||
|
export class PropertyString<X extends PackagePropertyString> {
|
||||||
|
private constructor(readonly data: X) {}
|
||||||
|
static of(value: {
|
||||||
|
description?: string;
|
||||||
|
value: string;
|
||||||
|
/** Let's the ui make this copyable button */
|
||||||
|
copyable?: boolean;
|
||||||
|
/** Let the ui create a qr for this field */
|
||||||
|
qr?: boolean;
|
||||||
|
/** Hiding the value unless toggled off for field */
|
||||||
|
masked?: boolean;
|
||||||
|
}) {
|
||||||
|
return new PropertyString({
|
||||||
|
...value,
|
||||||
|
type: "string",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
27
lib/properties/index.ts
Normal file
27
lib/properties/index.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { ExpectedExports, PackagePropertiesV2 } from "../types";
|
||||||
|
import "../util/extensions";
|
||||||
|
import { Properties } from "./Properties";
|
||||||
|
export { Properties } from "./Properties";
|
||||||
|
export { PropertyObject } from "./PropertyObject";
|
||||||
|
export { PropertyString } from "./PropertyString";
|
||||||
|
|
||||||
|
export const test = "";
|
||||||
|
export type UnionToIntersection<T> = ((x: T) => any) extends (x: infer R) => any
|
||||||
|
? R
|
||||||
|
: never;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used during creating the type of properties fn in the service package.
|
||||||
|
* This fn makes sure that the return type is correct and everything is infered to
|
||||||
|
* reduce the types that the user has to make.
|
||||||
|
* @param fn
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function setupPropertiesExport(
|
||||||
|
fn: (
|
||||||
|
...args: Parameters<ExpectedExports.properties>
|
||||||
|
) => Promise<Properties<PackagePropertiesV2>>
|
||||||
|
): ExpectedExports.properties {
|
||||||
|
return (...args: Parameters<ExpectedExports.properties>) =>
|
||||||
|
fn(...args).then((x) => x.build());
|
||||||
|
}
|
||||||
107
lib/types.ts
107
lib/types.ts
@@ -4,24 +4,39 @@ import { InputSpec } from "./config/configTypes";
|
|||||||
export namespace ExpectedExports {
|
export namespace ExpectedExports {
|
||||||
version: 1;
|
version: 1;
|
||||||
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
|
/** Set configuration is called after we have modified and saved the configuration in the embassy ui. Use this to make a file for the docker to read from for configuration. */
|
||||||
export type setConfig = (options: { effects: Effects; input: Record<string, unknown> }) => Promise<unknown>;
|
export type setConfig = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
input: Record<string, unknown>;
|
||||||
|
}) => Promise<unknown>;
|
||||||
/** Get configuration returns a shape that describes the format that the embassy ui will generate, and later send to the set config */
|
/** Get configuration returns a shape that describes the format that the embassy ui will generate, and later send to the set config */
|
||||||
export type getConfig = (options: { effects: Effects; config: unknown }) => Promise<ConfigRes>;
|
export type getConfig = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
config: unknown;
|
||||||
|
}) => Promise<ConfigRes>;
|
||||||
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
|
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
|
||||||
export type dependencies = Dependencies;
|
export type dependencies = Dependencies;
|
||||||
/** For backing up service data though the embassyOS UI */
|
/** For backing up service data though the embassyOS UI */
|
||||||
export type createBackup = (options: { effects: Effects }) => Promise<unknown>;
|
export type createBackup = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
}) => Promise<unknown>;
|
||||||
/** For restoring service data that was previously backed up using the embassyOS UI create backup flow. Backup restores are also triggered via the embassyOS UI, or doing a system restore flow during setup. */
|
/** For restoring service data that was previously backed up using the embassyOS UI create backup flow. Backup restores are also triggered via the embassyOS UI, or doing a system restore flow during setup. */
|
||||||
export type restoreBackup = (options: { effects: Effects }) => Promise<unknown>;
|
export type restoreBackup = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
}) => Promise<unknown>;
|
||||||
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
|
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
|
||||||
export type properties = (options: { effects: Effects }) => Promise<Properties>;
|
export type properties = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
}) => Promise<Properties | null | undefined | void>;
|
||||||
|
|
||||||
/** Health checks are used to determine if the service is working properly after starting
|
/** Health checks are used to determine if the service is working properly after starting
|
||||||
* A good use case is if we are using a web server, seeing if we can get to the web server.
|
* A good use case is if we are using a web server, seeing if we can get to the web server.
|
||||||
*/
|
*/
|
||||||
export type health = {
|
export type health = {
|
||||||
/** Should be the health check id */
|
/** Should be the health check id */
|
||||||
[id: string]: (options: { effects: Effects; input: TimeMs }) => Promise<unknown>;
|
[id: string]: (options: {
|
||||||
|
effects: Effects;
|
||||||
|
input: TimeMs;
|
||||||
|
}) => Promise<unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,29 +45,43 @@ export namespace ExpectedExports {
|
|||||||
* service starting, and that file would indicate that it would rescan all the data.
|
* service starting, and that file would indicate that it would rescan all the data.
|
||||||
*/
|
*/
|
||||||
export type action = {
|
export type action = {
|
||||||
[id: string]: (options: { effects: Effects; input?: Record<string, unknown> }) => Promise<ActionResult>;
|
[id: string]: (options: {
|
||||||
|
effects: Effects;
|
||||||
|
input?: Record<string, unknown>;
|
||||||
|
}) => Promise<ActionResult>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the entrypoint for the main container. Used to start up something like the service that the
|
* This is the entrypoint for the main container. Used to start up something like the service that the
|
||||||
* package represents, like running a bitcoind in a bitcoind-wrapper.
|
* package represents, like running a bitcoind in a bitcoind-wrapper.
|
||||||
*/
|
*/
|
||||||
export type main = (options: { effects: Effects; started(onTerm: () => void): null }) => Promise<unknown>;
|
export type main = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
started(onTerm: () => void): null;
|
||||||
|
}) => Promise<unknown>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Every time a package completes an install, this function is called before the main.
|
* Every time a package completes an install, this function is called before the main.
|
||||||
* Can be used to do migration like things.
|
* Can be used to do migration like things.
|
||||||
*/
|
*/
|
||||||
export type init = (options: { effects: Effects; previousVersion: null | string }) => Promise<unknown>;
|
export type init = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
previousVersion: null | string;
|
||||||
|
}) => Promise<unknown>;
|
||||||
/** This will be ran during any time a package is uninstalled, for example during a update
|
/** This will be ran during any time a package is uninstalled, for example during a update
|
||||||
* this will be called.
|
* this will be called.
|
||||||
*/
|
*/
|
||||||
export type uninit = (options: { effects: Effects; nextVersion: null | string }) => Promise<unknown>;
|
export type uninit = (options: {
|
||||||
|
effects: Effects;
|
||||||
|
nextVersion: null | string;
|
||||||
|
}) => Promise<unknown>;
|
||||||
}
|
}
|
||||||
export type TimeMs = number;
|
export type TimeMs = number;
|
||||||
export type VersionString = string;
|
export type VersionString = string;
|
||||||
|
|
||||||
export type ValidIfNoStupidEscape<A> = A extends `${string}'"'"'${string}` | `${string}\\"${string}`
|
export type ValidIfNoStupidEscape<A> = A extends
|
||||||
|
| `${string}'"'"'${string}`
|
||||||
|
| `${string}\\"${string}`
|
||||||
? never
|
? never
|
||||||
: "" extends A & ""
|
: "" extends A & ""
|
||||||
? never
|
? never
|
||||||
@@ -77,7 +106,9 @@ export type Daemon = {
|
|||||||
|
|
||||||
export type HealthStatus = "passing" | "warning" | "failing" | "disabled";
|
export type HealthStatus = "passing" | "warning" | "failing" | "disabled";
|
||||||
|
|
||||||
export type CommandType<A extends string> = ValidIfNoStupidEscape<A> | [string, ...string[]];
|
export type CommandType<A extends string> =
|
||||||
|
| ValidIfNoStupidEscape<A>
|
||||||
|
| [string, ...string[]];
|
||||||
|
|
||||||
export type DaemonReturned = {
|
export type DaemonReturned = {
|
||||||
wait(): Promise<string>;
|
wait(): Promise<string>;
|
||||||
@@ -87,7 +118,11 @@ export type DaemonReturned = {
|
|||||||
/** Used to reach out from the pure js runtime */
|
/** Used to reach out from the pure js runtime */
|
||||||
export type Effects = {
|
export type Effects = {
|
||||||
/** Usable when not sandboxed */
|
/** Usable when not sandboxed */
|
||||||
writeFile(input: { path: string; volumeId: string; toWrite: string }): Promise<void>;
|
writeFile(input: {
|
||||||
|
path: string;
|
||||||
|
volumeId: string;
|
||||||
|
toWrite: string;
|
||||||
|
}): Promise<void>;
|
||||||
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
||||||
metadata(input: { volumeId: string; path: string }): Promise<Metadata>;
|
metadata(input: { volumeId: string; path: string }): Promise<Metadata>;
|
||||||
/** Create a directory. Usable when not sandboxed */
|
/** Create a directory. Usable when not sandboxed */
|
||||||
@@ -99,10 +134,17 @@ export type Effects = {
|
|||||||
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
||||||
|
|
||||||
/** Write a json file into an object. Usable when not sandboxed */
|
/** Write a json file into an object. Usable when not sandboxed */
|
||||||
writeJsonFile(input: { volumeId: string; path: string; toWrite: Record<string, unknown> }): Promise<void>;
|
writeJsonFile(input: {
|
||||||
|
volumeId: string;
|
||||||
|
path: string;
|
||||||
|
toWrite: Record<string, unknown>;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
/** Read a json file into an object */
|
/** Read a json file into an object */
|
||||||
readJsonFile(input: { volumeId: string; path: string }): Promise<Record<string, unknown>>;
|
readJsonFile(input: {
|
||||||
|
volumeId: string;
|
||||||
|
path: string;
|
||||||
|
}): Promise<Record<string, unknown>>;
|
||||||
|
|
||||||
runCommand<A extends string>(
|
runCommand<A extends string>(
|
||||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||||
@@ -114,7 +156,9 @@ export type Effects = {
|
|||||||
wait(): Promise<string>;
|
wait(): Promise<string>;
|
||||||
term(): Promise<void>;
|
term(): Promise<void>;
|
||||||
};
|
};
|
||||||
runDaemon<A extends string>(command: ValidIfNoStupidEscape<A> | [string, ...string[]]): DaemonReturned;
|
runDaemon<A extends string>(
|
||||||
|
command: ValidIfNoStupidEscape<A> | [string, ...string[]]
|
||||||
|
): DaemonReturned;
|
||||||
|
|
||||||
/** Uses the chown on the system */
|
/** Uses the chown on the system */
|
||||||
chown(input: { volumeId: string; path: string; uid: string }): Promise<null>;
|
chown(input: { volumeId: string; path: string; uid: string }): Promise<null>;
|
||||||
@@ -142,7 +186,11 @@ export type Effects = {
|
|||||||
/** Declaring that we are opening a interface on some protocal for local network */
|
/** Declaring that we are opening a interface on some protocal for local network */
|
||||||
bindLan(options: { internalPort: number; name: string }): Promise<string[]>;
|
bindLan(options: { internalPort: number; name: string }): Promise<string[]>;
|
||||||
/** Declaring that we are opening a interface on some protocal for tor network */
|
/** Declaring that we are opening a interface on some protocal for tor network */
|
||||||
bindTor(options: { internalPort: number; name: string; externalPort: number }): Promise<string>;
|
bindTor(options: {
|
||||||
|
internalPort: number;
|
||||||
|
name: string;
|
||||||
|
externalPort: number;
|
||||||
|
}): Promise<string>;
|
||||||
|
|
||||||
/** Similar to the fetch api via the mdn, this is simplified but the point is
|
/** Similar to the fetch api via the mdn, this is simplified but the point is
|
||||||
* to get something from some website, and return the response.
|
* to get something from some website, and return the response.
|
||||||
@@ -192,11 +240,17 @@ export type Effects = {
|
|||||||
getLocalHostname(): Promise<string>;
|
getLocalHostname(): Promise<string>;
|
||||||
getIPHostname(): Promise<string>;
|
getIPHostname(): Promise<string>;
|
||||||
/** Get the address for another service for tor interfaces */
|
/** Get the address for another service for tor interfaces */
|
||||||
getServiceTorHostname(interfaceId: string, packageId?: string): Promise<string>;
|
getServiceTorHostname(
|
||||||
|
interfaceId: string,
|
||||||
|
packageId?: string
|
||||||
|
): Promise<string>;
|
||||||
/**
|
/**
|
||||||
* Get the port address for another service
|
* Get the port address for another service
|
||||||
*/
|
*/
|
||||||
getServicePortForward(internalPort: number, packageId?: string): Promise<number>;
|
getServicePortForward(
|
||||||
|
internalPort: number,
|
||||||
|
packageId?: string
|
||||||
|
): Promise<number>;
|
||||||
|
|
||||||
/** When we want to create a link in the front end interfaces, and example is
|
/** When we want to create a link in the front end interfaces, and example is
|
||||||
* exposing a url to view a web service
|
* exposing a url to view a web service
|
||||||
@@ -266,13 +320,20 @@ export type Effects = {
|
|||||||
*
|
*
|
||||||
* @returns PEM encoded fullchain (ecdsa)
|
* @returns PEM encoded fullchain (ecdsa)
|
||||||
*/
|
*/
|
||||||
getSslCertificate: (packageId: string, algorithm?: "ecdsa" | "ed25519") => [string, string, string];
|
getSslCertificate: (
|
||||||
|
packageId: string,
|
||||||
|
algorithm?: "ecdsa" | "ed25519"
|
||||||
|
) => [string, string, string];
|
||||||
/**
|
/**
|
||||||
* @returns PEM encoded ssl key (ecdsa)
|
* @returns PEM encoded ssl key (ecdsa)
|
||||||
*/
|
*/
|
||||||
getSslKey: (packageId: string, algorithm?: "ecdsa" | "ed25519") => string;
|
getSslKey: (packageId: string, algorithm?: "ecdsa" | "ed25519") => string;
|
||||||
|
|
||||||
setHealth(o: { name: string; status: HealthStatus; message?: string }): Promise<void>;
|
setHealth(o: {
|
||||||
|
name: string;
|
||||||
|
status: HealthStatus;
|
||||||
|
message?: string;
|
||||||
|
}): Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* rsync options: https://linux.die.net/man/1/rsync
|
/* rsync options: https://linux.die.net/man/1/rsync
|
||||||
@@ -396,4 +457,6 @@ export type Dependencies = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DeepPartial<T> = T extends {} ? { [P in keyof T]?: DeepPartial<T[P]> } : T;
|
export type DeepPartial<T> = T extends {}
|
||||||
|
? { [P in keyof T]?: DeepPartial<T[P]> }
|
||||||
|
: T;
|
||||||
|
|||||||
43
lib/util/extensions.ts
Normal file
43
lib/util/extensions.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
export type UnionToIntersection<T> = (
|
||||||
|
T extends any ? (x: T) => any : never
|
||||||
|
) extends (x: infer R) => any
|
||||||
|
? R
|
||||||
|
: never;
|
||||||
|
type _<A> = A;
|
||||||
|
type UnReadonly<A> = { -readonly [k in keyof A]: A[k] };
|
||||||
|
declare global {
|
||||||
|
interface Object {
|
||||||
|
entries<T extends {}>(
|
||||||
|
this: T
|
||||||
|
): Array<{ -readonly [K in keyof T]: [K, T[K]] }[keyof T]>;
|
||||||
|
values<T extends {}>(this: T): Array<T[keyof T]>;
|
||||||
|
keys<T extends {}>(this: T): Array<keyof T>;
|
||||||
|
}
|
||||||
|
interface Array<T> {
|
||||||
|
fromEntries(): UnionToIntersection<
|
||||||
|
T extends [infer Key, infer Value]
|
||||||
|
? { [k in Key extends string | number ? Key : never]: Value }
|
||||||
|
: never
|
||||||
|
>;
|
||||||
|
assignObject(): UnionToIntersection<T & {}>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.prototype.entries = function () {
|
||||||
|
return Object.entries(this) as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.prototype.values = function () {
|
||||||
|
return Object.values(this) as any;
|
||||||
|
};
|
||||||
|
Object.prototype.keys = function () {
|
||||||
|
return Object.keys(this) as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.fromEntries = function () {
|
||||||
|
return Object.fromEntries(this) as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.assignObject = function () {
|
||||||
|
return Object.assign({}, ...this) as any;
|
||||||
|
};
|
||||||
711
output.ts
711
output.ts
@@ -1,367 +1,476 @@
|
|||||||
|
import { Config, Value, List, Variants } from "start-sdk/config/builder";
|
||||||
import {Config, Value, List, Variants} from 'start-sdk/config/builder';
|
|
||||||
|
|
||||||
export const name = Value.string({
|
export const name = Value.string({
|
||||||
"name": "Node Name",
|
name: "Node Name",
|
||||||
"default": "Embassy LND",
|
default: "Embassy LND",
|
||||||
"description": "Name of this node in the list",
|
description: "Name of this node in the list",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"masked": false,
|
masked: false,
|
||||||
"placeholder": null,
|
placeholder: null,
|
||||||
"pattern": null,
|
pattern: null,
|
||||||
"patternDescription": null
|
patternDescription: null,
|
||||||
});
|
});
|
||||||
export const lnd = Config.of({"name": name,});;
|
export const lnd = Config.of({ name: name });
|
||||||
export const lightningNodesVariants = Variants.of({"lnd": {name: "lnd", spec: lnd},});
|
export const lightningNodesVariants = Variants.of({
|
||||||
export const lightningNodesUnion =
|
lnd: { name: "lnd", spec: lnd },
|
||||||
Value.union({
|
});
|
||||||
name: "Type",
|
export const lightningNodesUnion = Value.union(
|
||||||
description: "- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n",
|
{
|
||||||
warning: null,
|
name: "Type",
|
||||||
required: true,
|
description:
|
||||||
default: "lnd",
|
"- LND: Lightning Network Daemon from Lightning Labs\n- CLN: Core Lightning from Blockstream\n",
|
||||||
}, lightningNodesVariants)
|
warning: null,
|
||||||
;
|
required: true,
|
||||||
export const lightningNodesListConfig =
|
default: "lnd",
|
||||||
Config.of({
|
},
|
||||||
"union": lightningNodesUnion
|
lightningNodesVariants
|
||||||
})
|
);
|
||||||
;
|
export const lightningNodesListConfig = Config.of({
|
||||||
export const lightningNodesList = List.obj({
|
union: lightningNodesUnion,
|
||||||
name:"Lightning Nodes",
|
});
|
||||||
range:"[1,*)",
|
export const lightningNodesList = List.obj(
|
||||||
default: [],
|
{
|
||||||
description: "List of Lightning Network node instances to manage",
|
name: "Lightning Nodes",
|
||||||
warning: null,
|
range: "[1,*)",
|
||||||
}, {
|
default: [],
|
||||||
spec: lightningNodesListConfig,
|
description: "List of Lightning Network node instances to manage",
|
||||||
displayAs: "{{name}}",
|
warning: null,
|
||||||
uniqueBy: "name",
|
},
|
||||||
});
|
{
|
||||||
|
spec: lightningNodesListConfig,
|
||||||
|
displayAs: "{{name}}",
|
||||||
|
uniqueBy: "name",
|
||||||
|
}
|
||||||
|
);
|
||||||
export const testListUnion = Value.list(lightningNodesList);
|
export const testListUnion = Value.list(lightningNodesList);
|
||||||
export const enable = Value.boolean({
|
export const enable = Value.boolean({
|
||||||
"name": "Enable",
|
name: "Enable",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Allow remote RPC requests.",
|
description: "Allow remote RPC requests.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const username = Value.string({
|
export const username = Value.string({
|
||||||
"name": "Username",
|
name: "Username",
|
||||||
"default": "bitcoin",
|
default: "bitcoin",
|
||||||
"description": "The username for connecting to Bitcoin over RPC.",
|
description: "The username for connecting to Bitcoin over RPC.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"masked": true,
|
masked: true,
|
||||||
"placeholder": null,
|
placeholder: null,
|
||||||
"pattern": "^[a-zA-Z0-9_]+$",
|
pattern: "^[a-zA-Z0-9_]+$",
|
||||||
"patternDescription": "Must be alphanumeric (can contain underscore)."
|
patternDescription: "Must be alphanumeric (can contain underscore).",
|
||||||
});
|
});
|
||||||
export const password = Value.string({
|
export const password = Value.string({
|
||||||
"name": "RPC Password",
|
name: "RPC Password",
|
||||||
"default": {
|
default: {
|
||||||
"charset": "a-z,2-7",
|
charset: "a-z,2-7",
|
||||||
"len": 20
|
len: 20,
|
||||||
},
|
},
|
||||||
"description": "The password for connecting to Bitcoin over RPC.",
|
description: "The password for connecting to Bitcoin over RPC.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"masked": true,
|
masked: true,
|
||||||
"placeholder": null,
|
placeholder: null,
|
||||||
"pattern": "^[^\\n\"]*$",
|
pattern: '^[^\\n"]*$',
|
||||||
"patternDescription": "Must not contain newline or quote characters."
|
patternDescription: "Must not contain newline or quote characters.",
|
||||||
});
|
});
|
||||||
export const bio = Value.textarea({
|
export const bio = Value.textarea({
|
||||||
"name": "Username",
|
name: "Username",
|
||||||
"description": "The username for connecting to Bitcoin over RPC.",
|
description: "The username for connecting to Bitcoin over RPC.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const authorizationList = List.string({
|
export const authorizationList = List.string(
|
||||||
"name": "Authorization",
|
{
|
||||||
"range": "[0,*)",
|
name: "Authorization",
|
||||||
"default": [],
|
range: "[0,*)",
|
||||||
"description": "Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.",
|
default: [],
|
||||||
"warning": null
|
description:
|
||||||
}, {"masked":false,"placeholder":null,"pattern":"^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$","patternDescription":"Each item must be of the form \"<USERNAME>:<SALT>$<HASH>\"."});
|
"Username and hashed password for JSON-RPC connections. RPC clients connect using the usual http basic authentication.",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
masked: false,
|
||||||
|
placeholder: null,
|
||||||
|
pattern: "^[a-zA-Z0-9_-]+:([0-9a-fA-F]{2})+\\$([0-9a-fA-F]{2})+$",
|
||||||
|
patternDescription:
|
||||||
|
'Each item must be of the form "<USERNAME>:<SALT>$<HASH>".',
|
||||||
|
}
|
||||||
|
);
|
||||||
export const auth = Value.list(authorizationList);
|
export const auth = Value.list(authorizationList);
|
||||||
export const serialversion = Value.select({
|
export const serialversion = Value.select({
|
||||||
"name": "Serialization Version",
|
name: "Serialization Version",
|
||||||
"description": "Return raw transaction or block hex with Segwit or non-SegWit serialization.",
|
description:
|
||||||
"warning": null,
|
"Return raw transaction or block hex with Segwit or non-SegWit serialization.",
|
||||||
"default": "segwit",
|
warning: null,
|
||||||
"required": true,
|
default: "segwit",
|
||||||
"values": {
|
required: true,
|
||||||
|
values: {
|
||||||
"non-segwit": "non-segwit",
|
"non-segwit": "non-segwit",
|
||||||
"segwit": "segwit"
|
segwit: "segwit",
|
||||||
}
|
},
|
||||||
} as const);
|
} as const);
|
||||||
export const servertimeout = Value.number({
|
export const servertimeout = Value.number({
|
||||||
"name": "Rpc Server Timeout",
|
name: "Rpc Server Timeout",
|
||||||
"default": 30,
|
default: 30,
|
||||||
"description": "Number of seconds after which an uncompleted RPC call will time out.",
|
description:
|
||||||
"warning": null,
|
"Number of seconds after which an uncompleted RPC call will time out.",
|
||||||
"required": true,
|
warning: null,
|
||||||
"range": "[5,300]",
|
required: true,
|
||||||
"integral": true,
|
range: "[5,300]",
|
||||||
"units": "seconds",
|
integral: true,
|
||||||
"placeholder": null
|
units: "seconds",
|
||||||
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const threads = Value.number({
|
export const threads = Value.number({
|
||||||
"name": "Threads",
|
name: "Threads",
|
||||||
"default": 16,
|
default: 16,
|
||||||
"description": "Set the number of threads for handling RPC calls. You may wish to increase this if you are making lots of calls via an integration.",
|
description:
|
||||||
"warning": null,
|
"Set the number of threads for handling RPC calls. You may wish to increase this if you are making lots of calls via an integration.",
|
||||||
"required": true,
|
warning: null,
|
||||||
"range": "[1,64]",
|
required: true,
|
||||||
"integral": true,
|
range: "[1,64]",
|
||||||
"units": null,
|
integral: true,
|
||||||
"placeholder": null
|
units: null,
|
||||||
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const workqueue = Value.number({
|
export const workqueue = Value.number({
|
||||||
"name": "Work Queue",
|
name: "Work Queue",
|
||||||
"default": 128,
|
default: 128,
|
||||||
"description": "Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones.",
|
description:
|
||||||
"warning": null,
|
"Set the depth of the work queue to service RPC calls. Determines how long the backlog of RPC requests can get before it just rejects new ones.",
|
||||||
"required": true,
|
warning: null,
|
||||||
"range": "[8,256]",
|
required: true,
|
||||||
"integral": true,
|
range: "[8,256]",
|
||||||
"units": "requests",
|
integral: true,
|
||||||
"placeholder": null
|
units: "requests",
|
||||||
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const advancedSpec = Config.of({"auth": auth,"serialversion": serialversion,"servertimeout": servertimeout,"threads": threads,"workqueue": workqueue,});;
|
export const advancedSpec = Config.of({
|
||||||
export const advanced = Value.object({
|
auth: auth,
|
||||||
name: "Advanced",
|
serialversion: serialversion,
|
||||||
description: "Advanced RPC Settings",
|
servertimeout: servertimeout,
|
||||||
warning: null,
|
threads: threads,
|
||||||
}, advancedSpec);
|
workqueue: workqueue,
|
||||||
export const rpcSettingsSpec = Config.of({"enable": enable,"username": username,"password": password,"bio": bio,"advanced": advanced,});;
|
});
|
||||||
export const rpc = Value.object({
|
export const advanced = Value.object(
|
||||||
name: "RPC Settings",
|
{
|
||||||
description: "RPC configuration options.",
|
name: "Advanced",
|
||||||
warning: null,
|
description: "Advanced RPC Settings",
|
||||||
}, rpcSettingsSpec);
|
warning: null,
|
||||||
|
},
|
||||||
|
advancedSpec
|
||||||
|
);
|
||||||
|
export const rpcSettingsSpec = Config.of({
|
||||||
|
enable: enable,
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
bio: bio,
|
||||||
|
advanced: advanced,
|
||||||
|
});
|
||||||
|
export const rpc = Value.object(
|
||||||
|
{
|
||||||
|
name: "RPC Settings",
|
||||||
|
description: "RPC configuration options.",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
rpcSettingsSpec
|
||||||
|
);
|
||||||
export const zmqEnabled = Value.boolean({
|
export const zmqEnabled = Value.boolean({
|
||||||
"name": "ZeroMQ Enabled",
|
name: "ZeroMQ Enabled",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Enable the ZeroMQ interface",
|
description: "Enable the ZeroMQ interface",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const txindex = Value.boolean({
|
export const txindex = Value.boolean({
|
||||||
"name": "Transaction Index",
|
name: "Transaction Index",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Enable the Transaction Index (txindex)",
|
description: "Enable the Transaction Index (txindex)",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const enable1 = Value.boolean({
|
export const enable1 = Value.boolean({
|
||||||
"name": "Enable Wallet",
|
name: "Enable Wallet",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Load the wallet and enable wallet RPC calls.",
|
description: "Load the wallet and enable wallet RPC calls.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const avoidpartialspends = Value.boolean({
|
export const avoidpartialspends = Value.boolean({
|
||||||
"name": "Avoid Partial Spends",
|
name: "Avoid Partial Spends",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Group outputs by address, selecting all or none, instead of selecting on a per-output basis. This improves privacy at the expense of higher transaction fees.",
|
description:
|
||||||
"warning": null
|
"Group outputs by address, selecting all or none, instead of selecting on a per-output basis. This improves privacy at the expense of higher transaction fees.",
|
||||||
|
warning: null,
|
||||||
});
|
});
|
||||||
export const discardfee = Value.number({
|
export const discardfee = Value.number({
|
||||||
"name": "Discard Change Tolerance",
|
name: "Discard Change Tolerance",
|
||||||
"default": 0.0001,
|
default: 0.0001,
|
||||||
"description": "The fee rate (in BTC/kB) that indicates your tolerance for discarding change by adding it to the fee.",
|
description:
|
||||||
"warning": null,
|
"The fee rate (in BTC/kB) that indicates your tolerance for discarding change by adding it to the fee.",
|
||||||
"required": true,
|
warning: null,
|
||||||
"range": "[0,.01]",
|
required: true,
|
||||||
"integral": false,
|
range: "[0,.01]",
|
||||||
"units": "BTC/kB",
|
integral: false,
|
||||||
"placeholder": null
|
units: "BTC/kB",
|
||||||
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const walletSpec = Config.of({"enable": enable1,"avoidpartialspends": avoidpartialspends,"discardfee": discardfee,});;
|
export const walletSpec = Config.of({
|
||||||
export const wallet = Value.object({
|
enable: enable1,
|
||||||
name: "Wallet",
|
avoidpartialspends: avoidpartialspends,
|
||||||
description: "Wallet Settings",
|
discardfee: discardfee,
|
||||||
warning: null,
|
});
|
||||||
}, walletSpec);
|
export const wallet = Value.object(
|
||||||
|
{
|
||||||
|
name: "Wallet",
|
||||||
|
description: "Wallet Settings",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
walletSpec
|
||||||
|
);
|
||||||
export const mempoolfullrbf = Value.boolean({
|
export const mempoolfullrbf = Value.boolean({
|
||||||
"name": "Enable Full RBF",
|
name: "Enable Full RBF",
|
||||||
"default": false,
|
default: false,
|
||||||
"description": "Policy for your node to use for relaying and mining unconfirmed transactions. For details, see https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-24.0.md#notice-of-new-option-for-transaction-replacement-policies",
|
description:
|
||||||
"warning": null
|
"Policy for your node to use for relaying and mining unconfirmed transactions. For details, see https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-24.0.md#notice-of-new-option-for-transaction-replacement-policies",
|
||||||
|
warning: null,
|
||||||
});
|
});
|
||||||
export const persistmempool = Value.boolean({
|
export const persistmempool = Value.boolean({
|
||||||
"name": "Persist Mempool",
|
name: "Persist Mempool",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Save the mempool on shutdown and load on restart.",
|
description: "Save the mempool on shutdown and load on restart.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const maxmempool = Value.number({
|
export const maxmempool = Value.number({
|
||||||
"name": "Max Mempool Size",
|
name: "Max Mempool Size",
|
||||||
"default": 300,
|
default: 300,
|
||||||
"description": "Keep the transaction memory pool below <n> megabytes.",
|
description: "Keep the transaction memory pool below <n> megabytes.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"range": "[1,*)",
|
range: "[1,*)",
|
||||||
"integral": true,
|
integral: true,
|
||||||
"units": "MiB",
|
units: "MiB",
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const mempoolexpiry = Value.number({
|
export const mempoolexpiry = Value.number({
|
||||||
"name": "Mempool Expiration",
|
name: "Mempool Expiration",
|
||||||
"default": 336,
|
default: 336,
|
||||||
"description": "Do not keep transactions in the mempool longer than <n> hours.",
|
description: "Do not keep transactions in the mempool longer than <n> hours.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"range": "[1,*)",
|
range: "[1,*)",
|
||||||
"integral": true,
|
integral: true,
|
||||||
"units": "Hr",
|
units: "Hr",
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const mempoolSpec = Config.of({"mempoolfullrbf": mempoolfullrbf,"persistmempool": persistmempool,"maxmempool": maxmempool,"mempoolexpiry": mempoolexpiry,});;
|
export const mempoolSpec = Config.of({
|
||||||
export const mempool = Value.object({
|
mempoolfullrbf: mempoolfullrbf,
|
||||||
name: "Mempool",
|
persistmempool: persistmempool,
|
||||||
description: "Mempool Settings",
|
maxmempool: maxmempool,
|
||||||
warning: null,
|
mempoolexpiry: mempoolexpiry,
|
||||||
}, mempoolSpec);
|
});
|
||||||
|
export const mempool = Value.object(
|
||||||
|
{
|
||||||
|
name: "Mempool",
|
||||||
|
description: "Mempool Settings",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
mempoolSpec
|
||||||
|
);
|
||||||
export const listen = Value.boolean({
|
export const listen = Value.boolean({
|
||||||
"name": "Make Public",
|
name: "Make Public",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Allow other nodes to find your server on the network.",
|
description: "Allow other nodes to find your server on the network.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const onlyconnect = Value.boolean({
|
export const onlyconnect = Value.boolean({
|
||||||
"name": "Disable Peer Discovery",
|
name: "Disable Peer Discovery",
|
||||||
"default": false,
|
default: false,
|
||||||
"description": "Only connect to specified peers.",
|
description: "Only connect to specified peers.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const onlyonion = Value.boolean({
|
export const onlyonion = Value.boolean({
|
||||||
"name": "Disable Clearnet",
|
name: "Disable Clearnet",
|
||||||
"default": false,
|
default: false,
|
||||||
"description": "Only connect to peers over Tor.",
|
description: "Only connect to peers over Tor.",
|
||||||
"warning": null
|
warning: null,
|
||||||
});
|
});
|
||||||
export const hostname = Value.string({
|
export const hostname = Value.string({
|
||||||
"name": "Hostname",
|
name: "Hostname",
|
||||||
"default": null,
|
default: null,
|
||||||
"description": "Domain or IP address of bitcoin peer",
|
description: "Domain or IP address of bitcoin peer",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"masked": false,
|
masked: false,
|
||||||
"placeholder": null,
|
placeholder: null,
|
||||||
"pattern": "(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))",
|
pattern:
|
||||||
"patternDescription": "Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port."
|
"(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))",
|
||||||
|
patternDescription:
|
||||||
|
"Must be either a domain name, or an IPv4 or IPv6 address. Do not include protocol scheme (eg 'http://') or port.",
|
||||||
});
|
});
|
||||||
export const port = Value.number({
|
export const port = Value.number({
|
||||||
"name": "Port",
|
name: "Port",
|
||||||
"default": null,
|
default: null,
|
||||||
"description": "Port that peer is listening on for inbound p2p connections",
|
description: "Port that peer is listening on for inbound p2p connections",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": false,
|
required: false,
|
||||||
"range": "[0,65535]",
|
range: "[0,65535]",
|
||||||
"integral": true,
|
integral: true,
|
||||||
"units": null,
|
units: null,
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const addNodesSpec = Config.of({"hostname": hostname,"port": port,});;
|
export const addNodesSpec = Config.of({ hostname: hostname, port: port });
|
||||||
export const addNodesList = List.obj({
|
export const addNodesList = List.obj(
|
||||||
name: "Add Nodes",
|
{
|
||||||
range: "[0,*)",
|
name: "Add Nodes",
|
||||||
default: [],
|
range: "[0,*)",
|
||||||
description: "Add addresses of nodes to connect to.",
|
default: [],
|
||||||
warning: null,
|
description: "Add addresses of nodes to connect to.",
|
||||||
}, {
|
warning: null,
|
||||||
spec: addNodesSpec,
|
},
|
||||||
displayAs: null,
|
{
|
||||||
uniqueBy: null,
|
spec: addNodesSpec,
|
||||||
});
|
displayAs: null,
|
||||||
|
uniqueBy: null,
|
||||||
|
}
|
||||||
|
);
|
||||||
export const addnode = Value.list(addNodesList);
|
export const addnode = Value.list(addNodesList);
|
||||||
export const peersSpec = Config.of({"listen": listen,"onlyconnect": onlyconnect,"onlyonion": onlyonion,"addnode": addnode,});;
|
export const peersSpec = Config.of({
|
||||||
export const peers = Value.object({
|
listen: listen,
|
||||||
name: "Peers",
|
onlyconnect: onlyconnect,
|
||||||
description: "Peer Connection Settings",
|
onlyonion: onlyonion,
|
||||||
warning: null,
|
addnode: addnode,
|
||||||
}, peersSpec);
|
});
|
||||||
|
export const peers = Value.object(
|
||||||
|
{
|
||||||
|
name: "Peers",
|
||||||
|
description: "Peer Connection Settings",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
peersSpec
|
||||||
|
);
|
||||||
export const dbcache = Value.number({
|
export const dbcache = Value.number({
|
||||||
"name": "Database Cache",
|
name: "Database Cache",
|
||||||
"default": null,
|
default: null,
|
||||||
"description": "How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes.",
|
description:
|
||||||
"warning": "WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced. DO NOT press the STOP button if your dbcache is large. Instead, set this number back to the default, hit save, and wait for bitcoind to restart on its own.",
|
"How much RAM to allocate for caching the TXO set. Higher values improve syncing performance, but increase your chance of using up all your system's memory or corrupting your database in the event of an ungraceful shutdown. Set this high but comfortably below your system's total RAM during IBD, then turn down to 450 (or leave blank) once the sync completes.",
|
||||||
"required": false,
|
warning:
|
||||||
"range": "(0,*)",
|
"WARNING: Increasing this value results in a higher chance of ungraceful shutdowns, which can leave your node unusable if it happens during the initial block download. Use this setting with caution. Be sure to set this back to the default (450 or leave blank) once your node is synced. DO NOT press the STOP button if your dbcache is large. Instead, set this number back to the default, hit save, and wait for bitcoind to restart on its own.",
|
||||||
"integral": true,
|
required: false,
|
||||||
"units": "MiB",
|
range: "(0,*)",
|
||||||
"placeholder": null
|
integral: true,
|
||||||
|
units: "MiB",
|
||||||
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const disabled = Config.of({});;
|
export const disabled = Config.of({});
|
||||||
export const size = Value.number({
|
export const size = Value.number({
|
||||||
"name": "Max Chain Size",
|
name: "Max Chain Size",
|
||||||
"default": 550,
|
default: 550,
|
||||||
"description": "Limit of blockchain size on disk.",
|
description: "Limit of blockchain size on disk.",
|
||||||
"warning": "Increasing this value will require re-syncing your node.",
|
warning: "Increasing this value will require re-syncing your node.",
|
||||||
"required": true,
|
required: true,
|
||||||
"range": "[550,1000000)",
|
range: "[550,1000000)",
|
||||||
"integral": true,
|
integral: true,
|
||||||
"units": "MiB",
|
units: "MiB",
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const automatic = Config.of({"size": size,});;
|
export const automatic = Config.of({ size: size });
|
||||||
export const size1 = Value.number({
|
export const size1 = Value.number({
|
||||||
"name": "Failsafe Chain Size",
|
name: "Failsafe Chain Size",
|
||||||
"default": 65536,
|
default: 65536,
|
||||||
"description": "Prune blockchain if size expands beyond this.",
|
description: "Prune blockchain if size expands beyond this.",
|
||||||
"warning": null,
|
warning: null,
|
||||||
"required": true,
|
required: true,
|
||||||
"range": "[550,1000000)",
|
range: "[550,1000000)",
|
||||||
"integral": true,
|
integral: true,
|
||||||
"units": "MiB",
|
units: "MiB",
|
||||||
"placeholder": null
|
placeholder: null,
|
||||||
});
|
});
|
||||||
export const manual = Config.of({"size": size1,});;
|
export const manual = Config.of({ size: size1 });
|
||||||
export const pruningSettingsVariants = Variants.of({"disabled": {name: "Disabled", spec: disabled},"automatic": {name: "Automatic", spec: automatic},"manual": {name: "Manual", spec: manual},});
|
export const pruningSettingsVariants = Variants.of({
|
||||||
export const pruning = Value.union({
|
disabled: { name: "Disabled", spec: disabled },
|
||||||
name: "Pruning Settings",
|
automatic: { name: "Automatic", spec: automatic },
|
||||||
description: "- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the \"pruneblockchain\" RPC\n",
|
manual: { name: "Manual", spec: manual },
|
||||||
warning: null,
|
});
|
||||||
required: true,
|
export const pruning = Value.union(
|
||||||
default: "disabled",
|
{
|
||||||
}, pruningSettingsVariants);
|
name: "Pruning Settings",
|
||||||
|
description:
|
||||||
|
'- Disabled: Disable pruning\n- Automatic: Limit blockchain size on disk to a certain number of megabytes\n- Manual: Prune blockchain with the "pruneblockchain" RPC\n',
|
||||||
|
warning: null,
|
||||||
|
required: true,
|
||||||
|
default: "disabled",
|
||||||
|
},
|
||||||
|
pruningSettingsVariants
|
||||||
|
);
|
||||||
export const blockfilterindex = Value.boolean({
|
export const blockfilterindex = Value.boolean({
|
||||||
"name": "Compute Compact Block Filters (BIP158)",
|
name: "Compute Compact Block Filters (BIP158)",
|
||||||
"default": true,
|
default: true,
|
||||||
"description": "Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if dependent services need block filters to efficiently scan for addresses/transactions etc.",
|
description:
|
||||||
"warning": null
|
"Generate Compact Block Filters during initial sync (IBD) to enable 'getblockfilter' RPC. This is useful if dependent services need block filters to efficiently scan for addresses/transactions etc.",
|
||||||
|
warning: null,
|
||||||
});
|
});
|
||||||
export const peerblockfilters = Value.boolean({
|
export const peerblockfilters = Value.boolean({
|
||||||
"name": "Serve Compact Block Filters to Peers (BIP157)",
|
name: "Serve Compact Block Filters to Peers (BIP157)",
|
||||||
"default": false,
|
default: false,
|
||||||
"description": "Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to connect an SPV client to your node to make it efficient to scan transactions without having to download all block data. 'Compute Compact Block Filters (BIP158)' is required.",
|
description:
|
||||||
"warning": null
|
"Serve Compact Block Filters as a peer service to other nodes on the network. This is useful if you wish to connect an SPV client to your node to make it efficient to scan transactions without having to download all block data. 'Compute Compact Block Filters (BIP158)' is required.",
|
||||||
|
warning: null,
|
||||||
});
|
});
|
||||||
export const blockFiltersSpec = Config.of({"blockfilterindex": blockfilterindex,"peerblockfilters": peerblockfilters,});;
|
export const blockFiltersSpec = Config.of({
|
||||||
export const blockfilters = Value.object({
|
blockfilterindex: blockfilterindex,
|
||||||
name: "Block Filters",
|
peerblockfilters: peerblockfilters,
|
||||||
description: "Settings for storing and serving compact block filters",
|
});
|
||||||
warning: null,
|
export const blockfilters = Value.object(
|
||||||
}, blockFiltersSpec);
|
{
|
||||||
|
name: "Block Filters",
|
||||||
|
description: "Settings for storing and serving compact block filters",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
blockFiltersSpec
|
||||||
|
);
|
||||||
export const peerbloomfilters = Value.boolean({
|
export const peerbloomfilters = Value.boolean({
|
||||||
"name": "Serve Bloom Filters to Peers",
|
name: "Serve Bloom Filters to Peers",
|
||||||
"default": false,
|
default: false,
|
||||||
"description": "Peers have the option of setting filters on each connection they make after the version handshake has completed. Bloom filters are for clients implementing SPV (Simplified Payment Verification) that want to check that block headers connect together correctly, without needing to verify the full blockchain. The client must trust that the transactions in the chain are in fact valid. It is highly recommended AGAINST using for anything except Bisq integration.",
|
description:
|
||||||
"warning": "This is ONLY for use with Bisq integration, please use Block Filters for all other applications."
|
"Peers have the option of setting filters on each connection they make after the version handshake has completed. Bloom filters are for clients implementing SPV (Simplified Payment Verification) that want to check that block headers connect together correctly, without needing to verify the full blockchain. The client must trust that the transactions in the chain are in fact valid. It is highly recommended AGAINST using for anything except Bisq integration.",
|
||||||
|
warning:
|
||||||
|
"This is ONLY for use with Bisq integration, please use Block Filters for all other applications.",
|
||||||
|
});
|
||||||
|
export const bloomFiltersBip37Spec = Config.of({
|
||||||
|
peerbloomfilters: peerbloomfilters,
|
||||||
|
});
|
||||||
|
export const bloomfilters = Value.object(
|
||||||
|
{
|
||||||
|
name: "Bloom Filters (BIP37)",
|
||||||
|
description: "Setting for serving Bloom Filters",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
bloomFiltersBip37Spec
|
||||||
|
);
|
||||||
|
export const advancedSpec1 = Config.of({
|
||||||
|
mempool: mempool,
|
||||||
|
peers: peers,
|
||||||
|
dbcache: dbcache,
|
||||||
|
pruning: pruning,
|
||||||
|
blockfilters: blockfilters,
|
||||||
|
bloomfilters: bloomfilters,
|
||||||
|
});
|
||||||
|
export const advanced1 = Value.object(
|
||||||
|
{
|
||||||
|
name: "Advanced",
|
||||||
|
description: "Advanced Settings",
|
||||||
|
warning: null,
|
||||||
|
},
|
||||||
|
advancedSpec1
|
||||||
|
);
|
||||||
|
export const inputSpec = Config.of({
|
||||||
|
testListUnion: testListUnion,
|
||||||
|
rpc: rpc,
|
||||||
|
"zmq-enabled": zmqEnabled,
|
||||||
|
txindex: txindex,
|
||||||
|
wallet: wallet,
|
||||||
|
advanced: advanced1,
|
||||||
});
|
});
|
||||||
export const bloomFiltersBip37Spec = Config.of({"peerbloomfilters": peerbloomfilters,});;
|
|
||||||
export const bloomfilters = Value.object({
|
|
||||||
name: "Bloom Filters (BIP37)",
|
|
||||||
description: "Setting for serving Bloom Filters",
|
|
||||||
warning: null,
|
|
||||||
}, bloomFiltersBip37Spec);
|
|
||||||
export const advancedSpec1 = Config.of({"mempool": mempool,"peers": peers,"dbcache": dbcache,"pruning": pruning,"blockfilters": blockfilters,"bloomfilters": bloomfilters,});;
|
|
||||||
export const advanced1 = Value.object({
|
|
||||||
name: "Advanced",
|
|
||||||
description: "Advanced Settings",
|
|
||||||
warning: null,
|
|
||||||
}, advancedSpec1);
|
|
||||||
export const inputSpec = Config.of({"testListUnion": testListUnion,"rpc": rpc,"zmq-enabled": zmqEnabled,"txindex": txindex,"wallet": wallet,"advanced": advanced1,});;
|
|
||||||
export const matchInputSpec = inputSpec.validator();
|
export const matchInputSpec = inputSpec.validator();
|
||||||
export type InputSpec = typeof matchInputSpec._TYPE;
|
export type InputSpec = typeof matchInputSpec._TYPE;
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie14",
|
"version": "0.4.0-lib0.charlie15",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie14",
|
"version": "0.4.0-lib0.charlie15",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iarna/toml": "^2.2.5",
|
"@iarna/toml": "^2.2.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "start-sdk",
|
"name": "start-sdk",
|
||||||
"version": "0.4.0-lib0.charlie14",
|
"version": "0.4.0-lib0.charlie15",
|
||||||
"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",
|
||||||
|
|||||||
Reference in New Issue
Block a user