mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
Feat/js known errors (#1514)
* feat: known errors for js * chore: add expected exports * Update js_scripts.rs * chore: Use agreed upon shape * chore: add updates to d.ts * feat: error case * chore: Add expectedExports as a NameSpace` * chore: add more documentation to the types.d.ts
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
use std::{path::{PathBuf, Path}, time::Duration};
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use models::VolumeId;
|
use models::VolumeId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -12,20 +15,31 @@ use js_engine::{JsExecutionEnvironment, PathForVolumeId};
|
|||||||
|
|
||||||
use super::ProcedureName;
|
use super::ProcedureName;
|
||||||
|
|
||||||
pub use js_engine::{JsError};
|
pub use js_engine::JsError;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
|
||||||
|
enum ErrorValue {
|
||||||
|
Error(String),
|
||||||
|
Result(serde_json::Value),
|
||||||
|
}
|
||||||
|
|
||||||
impl PathForVolumeId for Volumes {
|
impl PathForVolumeId for Volumes {
|
||||||
fn path_for(&self, data_dir: &Path, package_id: &PackageId, version: &Version, volume_id: &VolumeId) -> Option<PathBuf> {
|
fn path_for(
|
||||||
|
&self,
|
||||||
|
data_dir: &Path,
|
||||||
|
package_id: &PackageId,
|
||||||
|
version: &Version,
|
||||||
|
volume_id: &VolumeId,
|
||||||
|
) -> Option<PathBuf> {
|
||||||
let volume = self.get(volume_id)?;
|
let volume = self.get(volume_id)?;
|
||||||
Some(volume.path_for(data_dir, package_id, version, volume_id))
|
Some(volume.path_for(data_dir, package_id, version, volume_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readonly(&self,volume_id: &VolumeId) -> bool {
|
fn readonly(&self, volume_id: &VolumeId) -> bool {
|
||||||
self.get(volume_id).map(|x| x.readonly()).unwrap_or(false)
|
self.get(volume_id).map(|x| x.readonly()).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
@@ -57,12 +71,13 @@ impl JsProcedure {
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
.run_action(name, input);
|
.run_action(name, input);
|
||||||
let output: O = match timeout {
|
let output: ErrorValue = match timeout {
|
||||||
Some(timeout_duration) => tokio::time::timeout(timeout_duration, running_action)
|
Some(timeout_duration) => tokio::time::timeout(timeout_duration, running_action)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| (JsError::Timeout, "Timed out. Retrying soon...".to_owned()))??,
|
.map_err(|_| (JsError::Timeout, "Timed out. Retrying soon...".to_owned()))??,
|
||||||
None => running_action.await?,
|
None => running_action.await?,
|
||||||
};
|
};
|
||||||
|
let output: O = unwrap_known_error(output)?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
.await
|
.await
|
||||||
@@ -90,12 +105,13 @@ impl JsProcedure {
|
|||||||
.await?
|
.await?
|
||||||
.read_only_effects()
|
.read_only_effects()
|
||||||
.run_action(name, input);
|
.run_action(name, input);
|
||||||
let output: O = match timeout {
|
let output: ErrorValue = match timeout {
|
||||||
Some(timeout_duration) => tokio::time::timeout(timeout_duration, running_action)
|
Some(timeout_duration) => tokio::time::timeout(timeout_duration, running_action)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| (JsError::Timeout, "Timed out. Retrying soon...".to_owned()))??,
|
.map_err(|_| (JsError::Timeout, "Timed out. Retrying soon...".to_owned()))??,
|
||||||
None => running_action.await?,
|
None => running_action.await?,
|
||||||
};
|
};
|
||||||
|
let output: O = unwrap_known_error(output)?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
.await
|
.await
|
||||||
@@ -103,6 +119,28 @@ impl JsProcedure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unwrap_known_error<O: for<'de> Deserialize<'de>>(
|
||||||
|
error_value: ErrorValue,
|
||||||
|
) -> Result<O, (JsError, String)> {
|
||||||
|
match error_value {
|
||||||
|
ErrorValue::Error(error) => Err((JsError::Javascript, error)),
|
||||||
|
ErrorValue::Result(ref value) => match serde_json::from_value(value.clone()) {
|
||||||
|
Ok(a) => Ok(a),
|
||||||
|
Err(err) => {
|
||||||
|
tracing::error!("{}", err);
|
||||||
|
tracing::debug!("{:?}", err);
|
||||||
|
Err((
|
||||||
|
JsError::BoundryLayerSerDe,
|
||||||
|
format!(
|
||||||
|
"Couldn't convert output = {:#?} to the correct type",
|
||||||
|
serde_json::to_string_pretty(&error_value).unwrap_or_default()
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn js_action_execute() {
|
async fn js_action_execute() {
|
||||||
let js_action = JsProcedure {};
|
let js_action = JsProcedure {};
|
||||||
@@ -157,3 +195,47 @@ async fn js_action_execute() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn js_action_execute_error() {
|
||||||
|
let js_action = JsProcedure {};
|
||||||
|
let path: PathBuf = "test/js_action_execute/"
|
||||||
|
.parse::<PathBuf>()
|
||||||
|
.unwrap()
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap();
|
||||||
|
let package_id = "test-package".parse().unwrap();
|
||||||
|
let package_version: Version = "0.3.0.3".parse().unwrap();
|
||||||
|
let name = ProcedureName::SetConfig;
|
||||||
|
let volumes: Volumes = serde_json::from_value(serde_json::json!({
|
||||||
|
"main": {
|
||||||
|
"type": "data"
|
||||||
|
},
|
||||||
|
"compat": {
|
||||||
|
"type": "assets"
|
||||||
|
},
|
||||||
|
"filebrowser" :{
|
||||||
|
"package-id": "filebrowser",
|
||||||
|
"path": "data",
|
||||||
|
"readonly": true,
|
||||||
|
"type": "pointer",
|
||||||
|
"volume-id": "main",
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
let input: Option<serde_json::Value> = None;
|
||||||
|
let timeout = Some(Duration::from_secs(10));
|
||||||
|
let output: Result<serde_json::Value, _> = js_action
|
||||||
|
.execute(
|
||||||
|
&path,
|
||||||
|
&package_id,
|
||||||
|
&package_version,
|
||||||
|
name,
|
||||||
|
&volumes,
|
||||||
|
input,
|
||||||
|
timeout,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!("Err((2, \"Not setup\"))", &format!("{:?}", output));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
import {Effects, Config, ConfigRes, SetResult, Properties} from './types';
|
|
||||||
|
|
||||||
|
|
||||||
export function properties(effects: Effects): Properties | Promise<Properties>;
|
|
||||||
export function getConfig(effects: Effects): ConfigRes | Promise<ConfigRes>;
|
|
||||||
export function setConfig(effects: Effects, input: Config): SetResult | Promise<SetResult>;
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,266 +0,0 @@
|
|||||||
export type Effects = {
|
|
||||||
writeFile(input: { path: string; volumeId: string; toWrite: string }): Promise<void>;
|
|
||||||
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
|
||||||
createDir(input: { volumeId: string; path: string }): Promise<string>;
|
|
||||||
removeDir(input: { volumeId: string; path: string }): Promise<string>;
|
|
||||||
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
|
||||||
writeJsonFile(input: { volumeId: string; path: string; toWrite: object }): Promise<void>;
|
|
||||||
readJsonFile(input: { volumeId: string; path: string }): Promise<object>;
|
|
||||||
trace(whatToPrin: string): void;
|
|
||||||
warn(whatToPrin: string): void;
|
|
||||||
error(whatToPrin: string): void;
|
|
||||||
debug(whatToPrin: string): void;
|
|
||||||
info(whatToPrin: string): void;
|
|
||||||
is_sandboxed(): boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ActionResult = {
|
|
||||||
version: "0";
|
|
||||||
message: string;
|
|
||||||
value?: string;
|
|
||||||
copyable: boolean;
|
|
||||||
qr: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ConfigRes = {
|
|
||||||
config?: Config;
|
|
||||||
spec: ConfigSpec;
|
|
||||||
};
|
|
||||||
export type Config = {
|
|
||||||
[value: string]: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ConfigSpec = {
|
|
||||||
[value: string]: ValueSpecAny;
|
|
||||||
};
|
|
||||||
export type WithDefault<T, Default> = T & {
|
|
||||||
default?: Default;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WithDescription<T> = T & {
|
|
||||||
description?: String;
|
|
||||||
name: string;
|
|
||||||
warning?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ListSpec<T> = {
|
|
||||||
spec: T;
|
|
||||||
range: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Tag<T extends string, V> = V & {
|
|
||||||
type: T;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Subtype<T extends string, V> = V & {
|
|
||||||
subtype: T;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Target<T extends string, V> = V & {
|
|
||||||
target: T;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UniqueBy =
|
|
||||||
| {
|
|
||||||
any: UniqueBy[];
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
all: UniqueBy[];
|
|
||||||
}
|
|
||||||
| string
|
|
||||||
| null;
|
|
||||||
|
|
||||||
export type WithNullable<T> = T & {
|
|
||||||
nullable: boolean;
|
|
||||||
};
|
|
||||||
export type DefaultString =
|
|
||||||
| String
|
|
||||||
| {
|
|
||||||
charset?: string;
|
|
||||||
len: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ValueSpecString = (
|
|
||||||
| {}
|
|
||||||
| {
|
|
||||||
pattern: string;
|
|
||||||
"pattern-description": string;
|
|
||||||
}
|
|
||||||
) & {
|
|
||||||
copyable?: boolean;
|
|
||||||
masked?: boolean;
|
|
||||||
placeholder?: string;
|
|
||||||
};
|
|
||||||
export type ValueSpecNumber = {
|
|
||||||
range?: string;
|
|
||||||
integral?: boolean;
|
|
||||||
units?: string;
|
|
||||||
placeholder?: number;
|
|
||||||
};
|
|
||||||
export type ValueSpecBoolean = {};
|
|
||||||
export type ValueSpecAny =
|
|
||||||
| Tag<"boolean", WithDescription<WithDefault<ValueSpecBoolean, boolean>>>
|
|
||||||
| Tag<"string", WithDescription<WithDefault<WithNullable<ValueSpecString>, DefaultString>>>
|
|
||||||
| Tag<"number", WithDescription<WithDefault<WithNullable<ValueSpecNumber>, number>>>
|
|
||||||
| Tag<
|
|
||||||
"enum",
|
|
||||||
WithDescription<
|
|
||||||
WithDefault<
|
|
||||||
{
|
|
||||||
values: string[];
|
|
||||||
"value-names": {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
string
|
|
||||||
>
|
|
||||||
>
|
|
||||||
>
|
|
||||||
| Tag<"list", ValueSpecList>
|
|
||||||
| Tag<"object", WithDescription<WithDefault<ValueSpecObject, Config>>>
|
|
||||||
| Tag<"union", WithDescription<WithDefault<ValueSpecUnion, string>>>
|
|
||||||
| Tag<
|
|
||||||
"pointer",
|
|
||||||
WithDescription<
|
|
||||||
| Subtype<
|
|
||||||
"package",
|
|
||||||
| Target<
|
|
||||||
"tor-key",
|
|
||||||
{
|
|
||||||
"package-id": string;
|
|
||||||
interface: string;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
| Target<
|
|
||||||
"tor-address",
|
|
||||||
{
|
|
||||||
"package-id": string;
|
|
||||||
interface: string;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
| Target<
|
|
||||||
"lan-address",
|
|
||||||
{
|
|
||||||
"package-id": string;
|
|
||||||
interface: string;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
| Target<
|
|
||||||
"config",
|
|
||||||
{
|
|
||||||
"package-id": string;
|
|
||||||
selector: string;
|
|
||||||
multi: boolean;
|
|
||||||
}
|
|
||||||
>
|
|
||||||
>
|
|
||||||
| Subtype<"system", {}>
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
export type ValueSpecUnion = {
|
|
||||||
tag: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
"variant-names": {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
variants: {
|
|
||||||
[key: string]: ConfigSpec;
|
|
||||||
};
|
|
||||||
"display-as"?: string;
|
|
||||||
"unique-by"?: UniqueBy;
|
|
||||||
};
|
|
||||||
export type ValueSpecObject = {
|
|
||||||
spec: ConfigSpec;
|
|
||||||
"display-as"?: string;
|
|
||||||
"unique-by"?: UniqueBy;
|
|
||||||
};
|
|
||||||
export type ValueSpecList =
|
|
||||||
| Subtype<"boolean", WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean>>>
|
|
||||||
| Subtype<"string", WithDescription<WithDefault<ListSpec<ValueSpecString>, string>>>
|
|
||||||
| Subtype<"number", WithDescription<WithDefault<ListSpec<ValueSpecNumber>, number>>>
|
|
||||||
| Subtype<
|
|
||||||
"enum",
|
|
||||||
WithDescription<
|
|
||||||
WithDefault<
|
|
||||||
{
|
|
||||||
values: string[];
|
|
||||||
"value-names": {
|
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
string
|
|
||||||
>
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type SetResult = {
|
|
||||||
signal:
|
|
||||||
| "SIGTERM"
|
|
||||||
| "SIGHUP"
|
|
||||||
| "SIGINT"
|
|
||||||
| "SIGQUIT"
|
|
||||||
| "SIGILL"
|
|
||||||
| "SIGTRAP"
|
|
||||||
| "SIGABRT"
|
|
||||||
| "SIGBUS"
|
|
||||||
| "SIGFPE"
|
|
||||||
| "SIGKILL"
|
|
||||||
| "SIGUSR1"
|
|
||||||
| "SIGSEGV"
|
|
||||||
| "SIGUSR2"
|
|
||||||
| "SIGPIPE"
|
|
||||||
| "SIGALRM"
|
|
||||||
| "SIGSTKFLT"
|
|
||||||
| "SIGCHLD"
|
|
||||||
| "SIGCONT"
|
|
||||||
| "SIGSTOP"
|
|
||||||
| "SIGTSTP"
|
|
||||||
| "SIGTTIN"
|
|
||||||
| "SIGTTOU"
|
|
||||||
| "SIGURG"
|
|
||||||
| "SIGXCPU"
|
|
||||||
| "SIGXFSZ"
|
|
||||||
| "SIGVTALRM"
|
|
||||||
| "SIGPROF"
|
|
||||||
| "SIGWINCH"
|
|
||||||
| "SIGIO"
|
|
||||||
| "SIGPWR"
|
|
||||||
| "SIGSYS"
|
|
||||||
| "SIGEMT"
|
|
||||||
| "SIGINFO";
|
|
||||||
"depends-on": {
|
|
||||||
[packageId: string]: string[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export type PackagePropertiesV2 = {
|
|
||||||
[name: string]: PackagePropertyObject | PackagePropertyString;
|
|
||||||
};
|
|
||||||
export type PackagePropertyString = {
|
|
||||||
type: "string";
|
|
||||||
description?: string;
|
|
||||||
value: string;
|
|
||||||
copyable?: boolean;
|
|
||||||
qr?: boolean;
|
|
||||||
masked?: boolean;
|
|
||||||
};
|
|
||||||
export type PackagePropertyObject = {
|
|
||||||
value: PackagePropertiesV2;
|
|
||||||
type: "object";
|
|
||||||
description: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Properties = {
|
|
||||||
version: 2;
|
|
||||||
data: PackagePropertiesV2;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type Dependencies = {
|
|
||||||
[id: string]: {
|
|
||||||
check(effects: Effects, input: Config): Promise<void | null>,
|
|
||||||
autoConfigure(effects: Effects, input: Config): Promise<Config>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
335
libs/artifacts/types.d.ts
vendored
Normal file
335
libs/artifacts/types.d.ts
vendored
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
export namespace ExpectedExports {
|
||||||
|
/** 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 = (
|
||||||
|
effects: Effects,
|
||||||
|
input: Config,
|
||||||
|
) => Promise<ResultType<SetResult>>;
|
||||||
|
/** 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 = (effects: Effects) => Promise<ResultType<ConfigRes>>;
|
||||||
|
/** These are how we make sure the our dependency configurations are valid and if not how to fix them. */
|
||||||
|
export type dependencies = Dependencies;
|
||||||
|
/** Properties are used to get values from the docker, like a username + password, what ports we are hosting from */
|
||||||
|
export type properties = (
|
||||||
|
effects: Effects,
|
||||||
|
) => Promise<ResultType<Properties>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to reach out from the pure js runtime */
|
||||||
|
export type Effects = {
|
||||||
|
/** Usable when not sandboxed */
|
||||||
|
writeFile(
|
||||||
|
input: { path: string; volumeId: string; toWrite: string },
|
||||||
|
): Promise<void>;
|
||||||
|
readFile(input: { volumeId: string; path: string }): Promise<string>;
|
||||||
|
/** Create a directory. Usable when not sandboxed */
|
||||||
|
createDir(input: { volumeId: string; path: string }): Promise<string>;
|
||||||
|
/** Remove a directory. Usable when not sandboxed */
|
||||||
|
removeDir(input: { volumeId: string; path: string }): Promise<string>;
|
||||||
|
removeFile(input: { volumeId: string; path: string }): Promise<void>;
|
||||||
|
|
||||||
|
/** Write a json file into an object. Usable when not sandboxed */
|
||||||
|
writeJsonFile(
|
||||||
|
input: { volumeId: string; path: string; toWrite: object },
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/** Read a json file into an object */
|
||||||
|
readJsonFile(input: { volumeId: string; path: string }): Promise<object>;
|
||||||
|
|
||||||
|
/** Log at the trace level */
|
||||||
|
trace(whatToPrint: string): void;
|
||||||
|
/** Log at the warn level */
|
||||||
|
warn(whatToPrint: string): void;
|
||||||
|
/** Log at the error level */
|
||||||
|
error(whatToPrint: string): void;
|
||||||
|
/** Log at the debug level */
|
||||||
|
debug(whatToPrint: string): void;
|
||||||
|
/** Log at the info level */
|
||||||
|
info(whatToPrint: string): void;
|
||||||
|
|
||||||
|
/** Sandbox mode lets us read but not write */
|
||||||
|
is_sandboxed(): boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ActionResult = {
|
||||||
|
version: "0";
|
||||||
|
message: string;
|
||||||
|
value?: string;
|
||||||
|
copyable: boolean;
|
||||||
|
qr: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConfigRes = {
|
||||||
|
/** This should be the previous config, that way during set config we start with the previous */
|
||||||
|
config?: Config;
|
||||||
|
/** Shape that is describing the form in the ui */
|
||||||
|
spec: ConfigSpec;
|
||||||
|
};
|
||||||
|
export type Config = {
|
||||||
|
[propertyName: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConfigSpec = {
|
||||||
|
/** Given a config value, define what it should render with the following spec */
|
||||||
|
[configValue: string]: ValueSpecAny;
|
||||||
|
};
|
||||||
|
export type WithDefault<T, Default> = T & {
|
||||||
|
default?: Default;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WithDescription<T> = T & {
|
||||||
|
description?: String;
|
||||||
|
name: string;
|
||||||
|
warning?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ListSpec<T> = {
|
||||||
|
spec: T;
|
||||||
|
range: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Tag<T extends string, V> = V & {
|
||||||
|
type: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Subtype<T extends string, V> = V & {
|
||||||
|
subtype: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Target<T extends string, V> = V & {
|
||||||
|
target: T;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UniqueBy =
|
||||||
|
| {
|
||||||
|
any: UniqueBy[];
|
||||||
|
}
|
||||||
|
| string
|
||||||
|
| null;
|
||||||
|
|
||||||
|
export type WithNullable<T> = T & {
|
||||||
|
nullable: boolean;
|
||||||
|
};
|
||||||
|
export type DefaultString =
|
||||||
|
| String
|
||||||
|
| {
|
||||||
|
/** The chars available for the randome generation */
|
||||||
|
charset?: string;
|
||||||
|
/** Length that we generate to */
|
||||||
|
len: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ValueSpecString =
|
||||||
|
& (
|
||||||
|
| {}
|
||||||
|
| {
|
||||||
|
pattern: string;
|
||||||
|
"pattern-description": string;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
& {
|
||||||
|
copyable?: boolean;
|
||||||
|
masked?: boolean;
|
||||||
|
placeholder?: string;
|
||||||
|
};
|
||||||
|
export type ValueSpecNumber = {
|
||||||
|
/** Something like [3,6] or [0, *) */
|
||||||
|
range?: string;
|
||||||
|
integral?: boolean;
|
||||||
|
/** Used a description of the units */
|
||||||
|
units?: string;
|
||||||
|
placeholder?: number;
|
||||||
|
};
|
||||||
|
export type ValueSpecBoolean = {};
|
||||||
|
export type ValueSpecAny =
|
||||||
|
| Tag<"boolean", WithDescription<WithDefault<ValueSpecBoolean, boolean>>>
|
||||||
|
| Tag<
|
||||||
|
"string",
|
||||||
|
WithDescription<WithDefault<WithNullable<ValueSpecString>, DefaultString>>
|
||||||
|
>
|
||||||
|
| Tag<
|
||||||
|
"number",
|
||||||
|
WithDescription<WithDefault<WithNullable<ValueSpecNumber>, number>>
|
||||||
|
>
|
||||||
|
| Tag<
|
||||||
|
"enum",
|
||||||
|
WithDescription<
|
||||||
|
WithDefault<
|
||||||
|
{
|
||||||
|
values: string[];
|
||||||
|
"value-names": {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
string
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
| Tag<"list", ValueSpecList>
|
||||||
|
| Tag<"object", WithDescription<WithDefault<ValueSpecObject, Config>>>
|
||||||
|
| Tag<"union", WithDescription<WithDefault<ValueSpecUnion, string>>>
|
||||||
|
| Tag<
|
||||||
|
"pointer",
|
||||||
|
WithDescription<
|
||||||
|
| Subtype<
|
||||||
|
"package",
|
||||||
|
| Target<
|
||||||
|
"tor-key",
|
||||||
|
{
|
||||||
|
"package-id": string;
|
||||||
|
interface: string;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
| Target<
|
||||||
|
"tor-address",
|
||||||
|
{
|
||||||
|
"package-id": string;
|
||||||
|
interface: string;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
| Target<
|
||||||
|
"lan-address",
|
||||||
|
{
|
||||||
|
"package-id": string;
|
||||||
|
interface: string;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
| Target<
|
||||||
|
"config",
|
||||||
|
{
|
||||||
|
"package-id": string;
|
||||||
|
selector: string;
|
||||||
|
multi: boolean;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
>
|
||||||
|
| Subtype<"system", {}>
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
export type ValueSpecUnion = {
|
||||||
|
/** What tag for the specification, for tag unions */
|
||||||
|
tag: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
"variant-names": {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** The possible enum values */
|
||||||
|
variants: {
|
||||||
|
[key: string]: ConfigSpec;
|
||||||
|
};
|
||||||
|
"display-as"?: string;
|
||||||
|
"unique-by"?: UniqueBy;
|
||||||
|
};
|
||||||
|
export type ValueSpecObject = {
|
||||||
|
spec: ConfigSpec;
|
||||||
|
"display-as"?: string;
|
||||||
|
"unique-by"?: UniqueBy;
|
||||||
|
};
|
||||||
|
export type ValueSpecList =
|
||||||
|
| Subtype<
|
||||||
|
"boolean",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecBoolean>, boolean>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"string",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecString>, string>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"number",
|
||||||
|
WithDescription<WithDefault<ListSpec<ValueSpecNumber>, number>>
|
||||||
|
>
|
||||||
|
| Subtype<
|
||||||
|
"enum",
|
||||||
|
WithDescription<
|
||||||
|
WithDefault<
|
||||||
|
{
|
||||||
|
values: string[];
|
||||||
|
"value-names": {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
string
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type SetResult = {
|
||||||
|
/** These are the unix process signals */
|
||||||
|
signal:
|
||||||
|
| "SIGTERM"
|
||||||
|
| "SIGHUP"
|
||||||
|
| "SIGINT"
|
||||||
|
| "SIGQUIT"
|
||||||
|
| "SIGILL"
|
||||||
|
| "SIGTRAP"
|
||||||
|
| "SIGABRT"
|
||||||
|
| "SIGBUS"
|
||||||
|
| "SIGFPE"
|
||||||
|
| "SIGKILL"
|
||||||
|
| "SIGUSR1"
|
||||||
|
| "SIGSEGV"
|
||||||
|
| "SIGUSR2"
|
||||||
|
| "SIGPIPE"
|
||||||
|
| "SIGALRM"
|
||||||
|
| "SIGSTKFLT"
|
||||||
|
| "SIGCHLD"
|
||||||
|
| "SIGCONT"
|
||||||
|
| "SIGSTOP"
|
||||||
|
| "SIGTSTP"
|
||||||
|
| "SIGTTIN"
|
||||||
|
| "SIGTTOU"
|
||||||
|
| "SIGURG"
|
||||||
|
| "SIGXCPU"
|
||||||
|
| "SIGXFSZ"
|
||||||
|
| "SIGVTALRM"
|
||||||
|
| "SIGPROF"
|
||||||
|
| "SIGWINCH"
|
||||||
|
| "SIGIO"
|
||||||
|
| "SIGPWR"
|
||||||
|
| "SIGSYS"
|
||||||
|
| "SIGEMT"
|
||||||
|
| "SIGINFO";
|
||||||
|
"depends-on": {
|
||||||
|
[packageId: string]: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type KnownError = { error: String };
|
||||||
|
export type ResultType<T> = KnownError | { result: T };
|
||||||
|
|
||||||
|
export type PackagePropertiesV2 = {
|
||||||
|
[name: string]: PackagePropertyObject | PackagePropertyString;
|
||||||
|
};
|
||||||
|
export type PackagePropertyString = {
|
||||||
|
type: "string";
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
export type PackagePropertyObject = {
|
||||||
|
value: PackagePropertiesV2;
|
||||||
|
type: "object";
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Properties = {
|
||||||
|
version: 2;
|
||||||
|
data: PackagePropertiesV2;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Dependencies = {
|
||||||
|
/** Id is the id of the package, should be the same as the manifest */
|
||||||
|
[id: string]: {
|
||||||
|
/** Checks are called to make sure that our dependency is in the correct shape. If a known error is returned we know that the dependency needs modification */
|
||||||
|
check(effects: Effects, input: Config): Promise<ResultType<void | null>>;
|
||||||
|
/** This is called after we know that the dependency package needs a new configuration, this would be a transform for defaults */
|
||||||
|
autoConfigure(effects: Effects, input: Config): Promise<ResultType<Config>>;
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user