mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
fix: Fix a lint
chore: remove the limit on the long-running fix: Starting sometimes. fix: Make it so the stop of the main works fix: Bind local and tor with package. wip: envs fix TS error import config types from sdk update package.json
This commit is contained in:
@@ -135,7 +135,7 @@ rust-argon2 = "1.0.0"
|
||||
scopeguard = "1.1" # because avahi-sys fucks your shit up
|
||||
serde = { version = "1.0.139", features = ["derive", "rc"] }
|
||||
serde_cbor = { package = "ciborium", version = "0.2.0" }
|
||||
serde_json = "1.0.82"
|
||||
serde_json = "1.0.93"
|
||||
serde_toml = { package = "toml", version = "0.5.9" }
|
||||
serde_with = { version = "2.0.1", features = ["macros", "json"] }
|
||||
serde_yaml = "0.9.11"
|
||||
|
||||
@@ -101,16 +101,28 @@ async fn create_service_manager(
|
||||
let mut running_service: Option<NonDetachingJoinHandle<()>> = None;
|
||||
let seed = seed.clone();
|
||||
loop {
|
||||
let current: StartStop = current_state.borrow().clone();
|
||||
let desired: StartStop = desired_state_receiver.borrow().clone();
|
||||
let current: StartStop = *current_state.borrow();
|
||||
let desired: StartStop = *desired_state_receiver.borrow();
|
||||
match (current, desired) {
|
||||
(StartStop::Start, StartStop::Start) => (),
|
||||
(StartStop::Start, StartStop::Stop) => {
|
||||
if let Err(err) = seed.stop_container().await {
|
||||
tracing::error!("Could not stop container");
|
||||
tracing::debug!("{:?}", err)
|
||||
};
|
||||
running_service = None;
|
||||
if persistent_container.is_none() {
|
||||
if let Err(err) = seed.stop_container().await {
|
||||
tracing::error!("Could not stop container");
|
||||
tracing::debug!("{:?}", err)
|
||||
}
|
||||
running_service = None;
|
||||
} else if let Some(current_service) = running_service.take() {
|
||||
tokio::select! {
|
||||
_ = current_service => (),
|
||||
_ = tokio::time::sleep(Duration::from_secs_f64(seed.manifest
|
||||
.containers
|
||||
.as_ref()
|
||||
.and_then(|c| c.main.sigterm_timeout).map(|x| x.as_secs_f64()).unwrap_or_default())) => {
|
||||
tracing::error!("Could not stop service");
|
||||
}
|
||||
}
|
||||
}
|
||||
current_state.send(StartStop::Stop).unwrap_or_default();
|
||||
}
|
||||
(StartStop::Stop, StartStop::Start) => starting_service(
|
||||
@@ -123,7 +135,7 @@ async fn create_service_manager(
|
||||
(StartStop::Stop, StartStop::Stop) => (),
|
||||
}
|
||||
|
||||
if let Err(_) = desired_state_receiver.changed().await {
|
||||
if desired_state_receiver.changed().await.is_err() {
|
||||
tracing::error!("Desired state error");
|
||||
break;
|
||||
}
|
||||
@@ -192,10 +204,7 @@ fn starting_service(
|
||||
current_state.send(StartStop::Start).unwrap_or_default();
|
||||
})
|
||||
};
|
||||
let set_stopped = {
|
||||
let current_state = current_state.clone();
|
||||
move || current_state.send(StartStop::Stop)
|
||||
};
|
||||
let set_stopped = { move || current_state.send(StartStop::Stop) };
|
||||
let running_main_loop = async move {
|
||||
while desired_state.borrow().is_start() {
|
||||
let result = run_main(
|
||||
|
||||
@@ -77,22 +77,25 @@ pub enum BackupReturn {
|
||||
}
|
||||
|
||||
pub struct Gid {
|
||||
next_gid: watch::Sender<u32>,
|
||||
main_gid: watch::Sender<ProcessGroupId>,
|
||||
next_gid: (watch::Sender<u32>, watch::Receiver<u32>),
|
||||
main_gid: (
|
||||
watch::Sender<ProcessGroupId>,
|
||||
watch::Receiver<ProcessGroupId>,
|
||||
),
|
||||
}
|
||||
|
||||
impl Default for Gid {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
next_gid: watch::channel(1).0,
|
||||
main_gid: watch::channel(ProcessGroupId(1)).0,
|
||||
next_gid: watch::channel(1),
|
||||
main_gid: watch::channel(ProcessGroupId(1)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Gid {
|
||||
pub fn new_gid(&self) -> ProcessGroupId {
|
||||
let mut previous = 0;
|
||||
self.next_gid.send_modify(|x| {
|
||||
self.next_gid.0.send_modify(|x| {
|
||||
previous = *x;
|
||||
*x = previous + 1;
|
||||
});
|
||||
@@ -101,7 +104,7 @@ impl Gid {
|
||||
|
||||
pub fn new_main_gid(&self) -> ProcessGroupId {
|
||||
let gid = self.new_gid();
|
||||
self.main_gid.send(gid).unwrap();
|
||||
self.main_gid.0.send(gid).unwrap_or_default();
|
||||
gid
|
||||
}
|
||||
}
|
||||
@@ -923,7 +926,7 @@ async fn send_signal(manager: &Manager, gid: Arc<Gid>, signal: Signal) -> Result
|
||||
// .store(false, Ordering::SeqCst);
|
||||
|
||||
if let Some(rpc_client) = manager.rpc_client() {
|
||||
let main_gid = *gid.main_gid.borrow();
|
||||
let main_gid = *gid.main_gid.0.borrow();
|
||||
let next_gid = gid.new_gid();
|
||||
#[cfg(feature = "js_engine")]
|
||||
if let Err(e) = crate::procedure::js_scripts::JsProcedure::default()
|
||||
|
||||
@@ -9,8 +9,8 @@ use tracing::instrument;
|
||||
|
||||
use super::manager_seed::ManagerSeed;
|
||||
use super::{
|
||||
add_network_for_main, generate_certificate, get_long_running_ip, long_running_docker,
|
||||
remove_network_for_main, GetRunningIp,
|
||||
add_network_for_main, get_long_running_ip, long_running_docker, remove_network_for_main,
|
||||
GetRunningIp,
|
||||
};
|
||||
use crate::procedure::docker::DockerContainer;
|
||||
use crate::util::NonDetachingJoinHandle;
|
||||
@@ -56,7 +56,8 @@ pub async fn spawn_persistent_container(
|
||||
let (mut runtime, inserter) =
|
||||
long_running_docker(&seed, &container).await?;
|
||||
|
||||
let ip = match get_long_running_ip(&*seed, &mut runtime).await {
|
||||
|
||||
let ip = match get_long_running_ip(&seed, &mut runtime).await {
|
||||
GetRunningIp::Ip(x) => x,
|
||||
GetRunningIp::Error(e) => return Err(e),
|
||||
GetRunningIp::EarlyExit(e) => {
|
||||
@@ -65,7 +66,7 @@ pub async fn spawn_persistent_container(
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
add_network_for_main(&*seed, ip, generated_certificate).await?;
|
||||
let svc = add_network_for_main(&seed, ip).await?;
|
||||
|
||||
if let Some(inserter_send) = inserter_send.as_mut() {
|
||||
let _ = inserter_send.send(Arc::new(inserter));
|
||||
@@ -81,7 +82,7 @@ pub async fn spawn_persistent_container(
|
||||
a = runtime.running_output => a.map_err(|_| Error::new(eyre!("Manager runtime panicked!"), crate::ErrorKind::Docker)).map(|_| ()),
|
||||
};
|
||||
|
||||
remove_network_for_main(&*seed, ip).await?;
|
||||
remove_network_for_main(svc).await?;
|
||||
|
||||
res
|
||||
}.await {
|
||||
|
||||
@@ -236,7 +236,7 @@ mod tests {
|
||||
use tokio::sync::watch;
|
||||
|
||||
struct OsApiMock {
|
||||
config_callbacks: watch::Sender<Vec<Callback>>,
|
||||
config_callbacks: (watch::Sender<Vec<Callback>>, watch::Sender<Vec<Callback>>),
|
||||
}
|
||||
impl Default for OsApiMock {
|
||||
fn default() -> Self {
|
||||
|
||||
@@ -93,13 +93,12 @@ impl PackageProcedure {
|
||||
ErrorKind::NotFound,
|
||||
)
|
||||
})?;
|
||||
let gid;
|
||||
let rpc_client = man.rpc_client();
|
||||
if matches!(name, ProcedureName::Main) {
|
||||
gid = man.gid.new_main_gid();
|
||||
let gid = if matches!(name, ProcedureName::Main) {
|
||||
man.gid.new_main_gid()
|
||||
} else {
|
||||
gid = man.gid.new_gid();
|
||||
}
|
||||
man.gid.new_gid()
|
||||
};
|
||||
|
||||
procedure
|
||||
.execute(
|
||||
|
||||
@@ -234,16 +234,6 @@ impl<R: AsyncRead + AsyncSeek + Unpin + Send + Sync> S9pkReader<R> {
|
||||
&validated_image_ids,
|
||||
)?;
|
||||
|
||||
#[cfg(feature = "js_engine")]
|
||||
if man.containers.is_some()
|
||||
|| matches!(man.main, crate::procedure::PackageProcedure::Script(_))
|
||||
{
|
||||
return Err(Error::new(
|
||||
eyre!("Right now we don't support the containers and the long running main"),
|
||||
crate::ErrorKind::ValidateS9pk,
|
||||
));
|
||||
}
|
||||
|
||||
if man.replaces.len() >= MAX_REPLACES {
|
||||
return Err(Error::new(
|
||||
eyre!("Cannot have more than {MAX_REPLACES} replaces"),
|
||||
|
||||
1935
frontend/package-lock.json
generated
1935
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,7 @@
|
||||
"patch-db-client": "file: ../../../patch-db/client",
|
||||
"pbkdf2": "^3.1.2",
|
||||
"rxjs": "^7.5.6",
|
||||
"start-sdk": "^0.4.0-lib0.alpha3",
|
||||
"swiper": "^8.2.4",
|
||||
"ts-matches": "^5.2.1",
|
||||
"tslib": "^2.3.0",
|
||||
@@ -103,7 +104,7 @@
|
||||
"raw-loader": "^4.0.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^4.6.3",
|
||||
"typescript": "^4.8.4",
|
||||
"webpack-bundle-analyzer": "^4.8.0"
|
||||
},
|
||||
"husky": {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
ModalController,
|
||||
} from '@ionic/angular'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
|
||||
@@ -285,31 +285,47 @@ const CifsSpec: ConfigSpec = {
|
||||
'pattern-description': `Must be a valid hostname. e.g. 'My Computer' OR 'my-computer.local'`,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
path: {
|
||||
type: 'string',
|
||||
name: 'Path',
|
||||
description: `On Windows, this is the fully qualified path to the shared folder, (e.g. /Desktop/my-folder).\n\n On Linux and Mac, this is the literal name of the shared folder (e.g. my-shared-folder).`,
|
||||
placeholder: 'e.g. my-shared-folder or /Desktop/my-folder',
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
username: {
|
||||
type: 'string',
|
||||
name: 'Username',
|
||||
description: `On Linux, this is the samba username you created when sharing the folder.\n\n On Mac and Windows, this is the username of the user who is sharing the folder.`,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
name: 'Password',
|
||||
description: `On Linux, this is the samba password you created when sharing the folder.\n\n On Mac and Windows, this is the password of the user who is sharing the folder.`,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: true,
|
||||
masked: true,
|
||||
copyable: false,
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -235,6 +235,7 @@
|
||||
name:
|
||||
objectListDisplay[entry.key][i].displayAs ||
|
||||
'Entry ' + (i + 1),
|
||||
description: null,
|
||||
new: false,
|
||||
edited: abstractControl.dirty
|
||||
}"
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
ValueSpecList,
|
||||
ValueSpecListOf,
|
||||
ValueSpecUnion,
|
||||
} from 'src/app/pkg-config/config-types'
|
||||
} from 'start-sdk/types/config-types'
|
||||
import { FormService } from 'src/app/services/form.service'
|
||||
import { EnumListPage } from 'src/app/modals/enum-list/enum-list.page'
|
||||
import { THEME, pauseFor } from '@start9labs/shared'
|
||||
@@ -249,7 +249,7 @@ export class FormObjectComponent {
|
||||
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: name,
|
||||
message: description,
|
||||
message: description || '',
|
||||
buttons: [
|
||||
{
|
||||
text: 'OK',
|
||||
@@ -395,7 +395,7 @@ export class FormLabelComponent {
|
||||
name: string
|
||||
new: boolean
|
||||
edited: boolean
|
||||
description?: string
|
||||
description: string | null
|
||||
required?: boolean
|
||||
newOptions?: boolean
|
||||
}
|
||||
@@ -408,7 +408,7 @@ export class FormLabelComponent {
|
||||
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: name,
|
||||
message: description,
|
||||
message: description || '',
|
||||
buttons: [
|
||||
{
|
||||
text: 'OK',
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
ValidationErrors,
|
||||
} from '@angular/forms'
|
||||
import { IonicSafeString } from '@ionic/angular'
|
||||
import { ListValueSpecOf } from 'src/app/pkg-config/config-types'
|
||||
import { Range } from 'src/app/pkg-config/config-utilities'
|
||||
import { ListValueSpecOf } from 'start-sdk/types/config-types'
|
||||
import { Range } from 'src/app/util/config-utilities'
|
||||
import { getElementId } from './form-object.component'
|
||||
|
||||
@Pipe({
|
||||
@@ -50,7 +50,7 @@ export class ToEnumListDisplayPipe implements PipeTransform {
|
||||
name: 'toWarningText',
|
||||
})
|
||||
export class ToWarningTextPipe implements PipeTransform {
|
||||
transform(text?: string): IonicSafeString | string {
|
||||
transform(text: string | null): IonicSafeString | string {
|
||||
return text
|
||||
? new IonicSafeString(`<ion-text color="warning">${text}</ion-text>`)
|
||||
: ''
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
isObject,
|
||||
} from '@start9labs/shared'
|
||||
import { DependentInfo } from 'src/app/types/dependent-info'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
@@ -100,13 +100,11 @@ export class AppConfigPage {
|
||||
}
|
||||
|
||||
this.configForm = this.formService.createForm(
|
||||
this.configSpec,
|
||||
this.configSpec!,
|
||||
newConfig || this.original,
|
||||
)
|
||||
|
||||
this.hasOptions = !!Object.values(this.configSpec).find(
|
||||
valSpec => valSpec.type !== 'pointer',
|
||||
)
|
||||
this.hasOptions = false
|
||||
|
||||
if (patch) {
|
||||
this.diff = this.getDiff(patch)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { ValueSpecListOf } from 'src/app/pkg-config/config-types'
|
||||
import { ValueSpecListOf } from 'start-sdk/types/config-types'
|
||||
|
||||
@Component({
|
||||
selector: 'enum-list',
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
convertValuesRecursive,
|
||||
FormService,
|
||||
} from 'src/app/services/form.service'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
|
||||
export interface ActionButton {
|
||||
text: string
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ActionSheetButton } from '@ionic/core'
|
||||
import { ErrorToastService, sameUrl, toUrl } from '@start9labs/shared'
|
||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
||||
import { ValueSpecObject } from 'start-sdk/types/config-types'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { DataModel, UIStore } from 'src/app/services/patch-db/data-model'
|
||||
@@ -259,6 +259,8 @@ function getMarketplaceValueSpec(): ValueSpecObject {
|
||||
return {
|
||||
type: 'object',
|
||||
name: 'Add Custom Registry',
|
||||
description: null,
|
||||
warning: null,
|
||||
spec: {
|
||||
url: {
|
||||
type: 'string',
|
||||
@@ -266,10 +268,12 @@ function getMarketplaceValueSpec(): ValueSpecObject {
|
||||
description: 'A fully-qualified URL of the custom registry',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: `https?:\/\/[a-zA-Z0-9][a-zA-Z0-9-\.]+[a-zA-Z0-9]\.[^\s]{2,}`,
|
||||
'pattern-description': 'Must be a valid URL',
|
||||
placeholder: 'e.g. https://example.org',
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from 'src/app/modals/generic-input/generic-input.component'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { v4 } from 'uuid'
|
||||
import { DataModel, DevData } from 'src/app/services/patch-db/data-model'
|
||||
@@ -223,12 +223,14 @@ const SAMPLE_CONFIG: ConfigSpec = {
|
||||
name: 'Example String Input',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
// optional
|
||||
description: 'Example description for required string input.',
|
||||
placeholder: 'Enter string value',
|
||||
pattern: '^[a-zA-Z0-9! _]+$',
|
||||
'pattern-description': 'Must be alphanumeric (may contain underscore).',
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'sample-number': {
|
||||
type: 'number',
|
||||
@@ -241,6 +243,7 @@ const SAMPLE_CONFIG: ConfigSpec = {
|
||||
units: 'ms',
|
||||
description: 'Example description for optional number input.',
|
||||
placeholder: 'Enter number value',
|
||||
default: null,
|
||||
},
|
||||
'sample-boolean': {
|
||||
type: 'boolean',
|
||||
@@ -248,6 +251,7 @@ const SAMPLE_CONFIG: ConfigSpec = {
|
||||
// optional
|
||||
description: 'Example description for boolean toggle',
|
||||
default: true,
|
||||
warning: null,
|
||||
},
|
||||
'sample-enum': {
|
||||
type: 'enum',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import { DevProjectData } from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export type BasicInfo = {
|
||||
@@ -27,10 +27,11 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
placeholder: 'e.g. bitcoind',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
|
||||
'pattern-description': 'Must be kebab case',
|
||||
default: basicInfo?.id,
|
||||
default: basicInfo?.id || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
@@ -39,8 +40,11 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
placeholder: 'e.g. Bitcoin Core',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
default: basicInfo ? basicInfo.title : devData.name,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'service-version-number': {
|
||||
type: 'string',
|
||||
@@ -50,39 +54,44 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
placeholder: 'e.g. 0.1.2.3',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: '^([0-9]+).([0-9]+).([0-9]+).([0-9]+)$',
|
||||
'pattern-description': 'Must be valid Emver version',
|
||||
default: basicInfo?.['service-version-number'],
|
||||
default: basicInfo?.['service-version-number'] || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
description: {
|
||||
type: 'object',
|
||||
name: 'Marketplace Descriptions',
|
||||
description: null,
|
||||
warning: null,
|
||||
spec: {
|
||||
short: {
|
||||
type: 'string',
|
||||
name: 'Short Description',
|
||||
description:
|
||||
'This is the first description visible to the user in the marketplace',
|
||||
placeholder: null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
textarea: true,
|
||||
default: basicInfo?.description?.short,
|
||||
default: basicInfo?.description?.short || '',
|
||||
pattern: '^.{1,320}$',
|
||||
'pattern-description': 'Must be shorter than 320 characters',
|
||||
warning: null,
|
||||
},
|
||||
long: {
|
||||
type: 'string',
|
||||
name: 'Long Description',
|
||||
description: `This description will display with additional details in the service's individual marketplace page`,
|
||||
placeholder: null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
textarea: true,
|
||||
default: basicInfo?.description?.long,
|
||||
default: basicInfo?.description?.long || '',
|
||||
pattern: '^.{1,5000}$',
|
||||
'pattern-description': 'Must be shorter than 5000 characters',
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -94,13 +103,16 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
placeholder: 'e.g. Markdown _release notes_ for **Bitcoin Core**',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: true,
|
||||
default: basicInfo?.['release-notes'],
|
||||
default: basicInfo?.['release-notes'] || '',
|
||||
warning: null,
|
||||
},
|
||||
license: {
|
||||
type: 'enum',
|
||||
name: 'License',
|
||||
warning: null,
|
||||
values: [
|
||||
'gnu-agpl-v3',
|
||||
'gnu-gpl-v3',
|
||||
@@ -132,40 +144,52 @@ export function getBasicInfoSpec(devData: DevProjectData): ConfigSpec {
|
||||
description:
|
||||
'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',
|
||||
placeholder: 'e.g. www.github.com/example',
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: basicInfo?.['wrapper-repo'],
|
||||
default: basicInfo?.['wrapper-repo'] || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'upstream-repo': {
|
||||
type: 'string',
|
||||
name: 'Upstream Repo',
|
||||
description: 'The original project repository URL',
|
||||
placeholder: 'e.g. www.github.com/example',
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: basicInfo?.['upstream-repo'],
|
||||
default: basicInfo?.['upstream-repo'] || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'support-site': {
|
||||
type: 'string',
|
||||
name: 'Support Site',
|
||||
description: 'URL to the support site / channel for the project',
|
||||
placeholder: 'e.g. start9.com/support',
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: basicInfo?.['support-site'],
|
||||
default: basicInfo?.['support-site'] || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'marketing-site': {
|
||||
type: 'string',
|
||||
name: 'Marketing Site',
|
||||
description: 'URL to the marketing site / channel for the project',
|
||||
placeholder: 'e.g. start9.com',
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: basicInfo?.['marketing-site'],
|
||||
default: basicInfo?.['marketing-site'] || '',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ export class SideloadPage {
|
||||
const guid = await this.api.sideloadPackage({
|
||||
manifest: this.toUpload.manifest!,
|
||||
icon: this.toUpload.icon!,
|
||||
size: this.toUpload.file!.size,
|
||||
})
|
||||
this.api
|
||||
.uploadPackage(guid, this.toUpload.file!)
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { AlertInput } from '@ionic/core'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ActionSheetButton } from '@ionic/core'
|
||||
import { ValueSpecObject } from 'src/app/pkg-config/config-types'
|
||||
import { ValueSpecObject } from 'start-sdk/types/config-types'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { pauseFor, ErrorToastService } from '@start9labs/shared'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
@@ -345,23 +345,33 @@ function getWifiValueSpec(
|
||||
name: 'WiFi Credentials',
|
||||
description:
|
||||
'Enter the network SSID and password. You can connect now or save the network for later.',
|
||||
warning: null,
|
||||
spec: {
|
||||
ssid: {
|
||||
type: 'string',
|
||||
name: 'Network SSID',
|
||||
description: null,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
default: ssid,
|
||||
default: ssid || null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
password: {
|
||||
type: 'string',
|
||||
name: 'Password',
|
||||
description: null,
|
||||
placeholder: null,
|
||||
nullable: !needsPW,
|
||||
masked: true,
|
||||
copyable: false,
|
||||
pattern: '^.{8,}$',
|
||||
'pattern-description': 'Must be longer than 8 characters',
|
||||
default: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
export type ConfigSpec = Record<string, ValueSpec>
|
||||
|
||||
export type ValueType =
|
||||
| 'string'
|
||||
| 'number'
|
||||
| 'boolean'
|
||||
| 'enum'
|
||||
| 'list'
|
||||
| 'object'
|
||||
| 'union'
|
||||
export type ValueSpec = ValueSpecOf<ValueType>
|
||||
|
||||
// core spec types. These types provide the metadata for performing validations
|
||||
export type ValueSpecOf<T extends ValueType> = T extends 'string'
|
||||
? ValueSpecString
|
||||
: T extends 'number'
|
||||
? ValueSpecNumber
|
||||
: T extends 'boolean'
|
||||
? ValueSpecBoolean
|
||||
: T extends 'enum'
|
||||
? ValueSpecEnum
|
||||
: T extends 'list'
|
||||
? ValueSpecList
|
||||
: T extends 'object'
|
||||
? ValueSpecObject
|
||||
: T extends 'union'
|
||||
? ValueSpecUnion
|
||||
: never
|
||||
|
||||
export interface ValueSpecString extends ListValueSpecString, WithStandalone {
|
||||
type: 'string'
|
||||
default?: DefaultString
|
||||
nullable: boolean
|
||||
textarea?: boolean
|
||||
}
|
||||
|
||||
export interface ValueSpecNumber extends ListValueSpecNumber, WithStandalone {
|
||||
type: 'number'
|
||||
nullable: boolean
|
||||
default?: number
|
||||
}
|
||||
|
||||
export interface ValueSpecEnum extends ListValueSpecEnum, WithStandalone {
|
||||
type: 'enum'
|
||||
default: string
|
||||
}
|
||||
|
||||
export interface ValueSpecBoolean extends WithStandalone {
|
||||
type: 'boolean'
|
||||
default: boolean
|
||||
}
|
||||
|
||||
export interface ValueSpecUnion {
|
||||
type: 'union'
|
||||
tag: UnionTagSpec
|
||||
variants: { [key: string]: ConfigSpec }
|
||||
default: string
|
||||
}
|
||||
|
||||
export interface ValueSpecObject extends WithStandalone {
|
||||
type: 'object'
|
||||
spec: ConfigSpec
|
||||
}
|
||||
|
||||
export interface WithStandalone {
|
||||
name: string
|
||||
description?: string
|
||||
warning?: string
|
||||
}
|
||||
|
||||
// no lists of booleans or lists
|
||||
export type ListValueSpecType =
|
||||
| 'string'
|
||||
| 'number'
|
||||
| 'enum'
|
||||
| 'object'
|
||||
| 'union'
|
||||
|
||||
// represents a spec for the values of a list
|
||||
export type ListValueSpecOf<T extends ListValueSpecType> = T extends 'string'
|
||||
? ListValueSpecString
|
||||
: T extends 'number'
|
||||
? ListValueSpecNumber
|
||||
: T extends 'enum'
|
||||
? ListValueSpecEnum
|
||||
: T extends 'object'
|
||||
? ListValueSpecObject
|
||||
: T extends 'union'
|
||||
? ListValueSpecUnion
|
||||
: never
|
||||
|
||||
// represents a spec for a list
|
||||
export type ValueSpecList = ValueSpecListOf<ListValueSpecType>
|
||||
export interface ValueSpecListOf<T extends ListValueSpecType>
|
||||
extends WithStandalone {
|
||||
type: 'list'
|
||||
subtype: T
|
||||
spec: ListValueSpecOf<T>
|
||||
range: string // '[0,1]' (inclusive) OR '[0,*)' (right unbounded), normal math rules
|
||||
default: string[] | number[] | DefaultString[] | object[]
|
||||
}
|
||||
|
||||
// sometimes the type checker needs just a little bit of help
|
||||
export function isValueSpecListOf<S extends ListValueSpecType>(
|
||||
t: ValueSpecList,
|
||||
s: S,
|
||||
): t is ValueSpecListOf<S> {
|
||||
return t.subtype === s
|
||||
}
|
||||
|
||||
export interface ListValueSpecString {
|
||||
pattern?: string
|
||||
'pattern-description'?: string
|
||||
masked: boolean
|
||||
copyable: boolean
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
export interface ListValueSpecNumber {
|
||||
range: string
|
||||
integral: boolean
|
||||
units?: string
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
export interface ListValueSpecEnum {
|
||||
values: string[]
|
||||
'value-names': { [value: string]: string }
|
||||
}
|
||||
|
||||
export interface ListValueSpecObject {
|
||||
spec: ConfigSpec // this is a mapped type of the config object at this level, replacing the object's values with specs on those values
|
||||
'unique-by': UniqueBy // indicates whether duplicates can be permitted in the list
|
||||
'display-as'?: string // this should be a handlebars template which can make use of the entire config which corresponds to 'spec'
|
||||
}
|
||||
|
||||
export type UniqueBy = null | string | { any: UniqueBy[] } | { all: UniqueBy[] }
|
||||
|
||||
export interface ListValueSpecUnion {
|
||||
tag: UnionTagSpec
|
||||
variants: { [key: string]: ConfigSpec }
|
||||
'display-as'?: string // this may be a handlebars template which can conditionally (on tag.id) make use of each union's entries, or if left blank will display as tag.id
|
||||
'unique-by': UniqueBy
|
||||
default: string // this should be the variantName which one prefers a user to start with by default when creating a new union instance in a list
|
||||
}
|
||||
|
||||
export interface UnionTagSpec {
|
||||
id: string // The name of the field containing one of the union variants
|
||||
'variant-names': {
|
||||
// the name of each variant
|
||||
[variant: string]: string
|
||||
}
|
||||
name: string
|
||||
description?: string
|
||||
warning?: string
|
||||
}
|
||||
|
||||
export type DefaultString = string | { charset: string; len: number }
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
PackageState,
|
||||
ServerStatusInfo,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { Metric, NotificationLevel, RR, ServerNotifications } from './api.types'
|
||||
|
||||
import { Metric, RR, NotificationLevel, ServerNotifications } from './api.types'
|
||||
import { BTC_ICON, LND_ICON, PROXY_ICON } from './api-icons'
|
||||
import { DependencyMetadata, MarketplacePkg } from '@start9labs/marketplace'
|
||||
import { Log } from '@start9labs/shared'
|
||||
@@ -180,11 +179,14 @@ export module Mock {
|
||||
type: 'string',
|
||||
name: 'Re-sync Reason',
|
||||
description: 'Your reason for re-syncing. Why are you doing this?',
|
||||
placeholder: null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: '^[a-zA-Z]+$',
|
||||
'pattern-description': 'Must contain only letters.',
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
@@ -192,14 +194,19 @@ export module Mock {
|
||||
description: 'Tell the class your name.',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
warning: 'You may loose all your money by providing your name.',
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
default: null,
|
||||
},
|
||||
notifications: {
|
||||
name: 'Notification Preferences',
|
||||
type: 'list',
|
||||
subtype: 'enum',
|
||||
description: 'how you want to be notified',
|
||||
warning: null,
|
||||
range: '[1,3]',
|
||||
default: ['email'],
|
||||
spec: {
|
||||
@@ -221,6 +228,9 @@ export module Mock {
|
||||
default: 100,
|
||||
range: '[0, 9999]',
|
||||
integral: true,
|
||||
units: null,
|
||||
placeholder: null,
|
||||
warning: null,
|
||||
},
|
||||
'top-speed': {
|
||||
type: 'number',
|
||||
@@ -230,6 +240,9 @@ export module Mock {
|
||||
range: '[-1000, 1000]',
|
||||
integral: false,
|
||||
units: 'm/s',
|
||||
placeholder: null,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
testnet: {
|
||||
name: 'Testnet',
|
||||
@@ -257,22 +270,33 @@ export module Mock {
|
||||
name: 'Emergency Contact',
|
||||
type: 'object',
|
||||
description: 'The person to contact in case of emergency.',
|
||||
warning: null,
|
||||
spec: {
|
||||
name: {
|
||||
type: 'string',
|
||||
name: 'Name',
|
||||
description: null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
pattern: '^[a-zA-Z]+$',
|
||||
'pattern-description': 'Must contain only letters.',
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
name: 'Email',
|
||||
description: null,
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -287,10 +311,10 @@ export module Mock {
|
||||
range: '[1,10]',
|
||||
default: ['192.168.1.1'],
|
||||
spec: {
|
||||
placeholder: null,
|
||||
pattern: '^[0-9]{1,3}([,.][0-9]{1,3})?$',
|
||||
'pattern-description': 'Must be a valid IP address',
|
||||
masked: false,
|
||||
copyable: false,
|
||||
},
|
||||
},
|
||||
bitcoinNode: {
|
||||
@@ -314,7 +338,12 @@ export module Mock {
|
||||
description: 'the lan address',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
external: {
|
||||
@@ -327,7 +356,9 @@ export module Mock {
|
||||
pattern: '.*',
|
||||
'pattern-description': 'anything',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1281,6 +1312,7 @@ export module Mock {
|
||||
type: 'list',
|
||||
subtype: 'object',
|
||||
description: 'This is a list of objects, like users or something',
|
||||
warning: null,
|
||||
range: '[0,4]',
|
||||
default: [
|
||||
{
|
||||
@@ -1307,7 +1339,12 @@ export module Mock {
|
||||
description: 'User first name',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
'last-name': {
|
||||
name: 'Last Name',
|
||||
@@ -1321,7 +1358,9 @@ export module Mock {
|
||||
pattern: '^[a-zA-Z]+$',
|
||||
'pattern-description': 'must contain only letters.',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
age: {
|
||||
name: 'Age',
|
||||
@@ -1331,6 +1370,9 @@ export module Mock {
|
||||
integral: false,
|
||||
warning: 'User must be at least 18.',
|
||||
range: '[18,*)',
|
||||
units: null,
|
||||
placeholder: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1347,6 +1389,8 @@ export module Mock {
|
||||
spec: {
|
||||
tag: {
|
||||
id: 'preference',
|
||||
description: null,
|
||||
warning: null,
|
||||
'variant-names': {
|
||||
summer: 'Summer',
|
||||
winter: 'Winter',
|
||||
@@ -1354,6 +1398,7 @@ export module Mock {
|
||||
},
|
||||
name: 'Preference',
|
||||
},
|
||||
'display-as': null,
|
||||
// this default is used to make a union selection when a new list element is first created
|
||||
default: 'summer',
|
||||
variants: {
|
||||
@@ -1365,12 +1410,17 @@ export module Mock {
|
||||
description: 'What is your favorite tree?',
|
||||
default: 'Maple',
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'favorite-flower': {
|
||||
name: 'Favorite Flower',
|
||||
type: 'enum',
|
||||
description: 'Select your favorite flower',
|
||||
warning: null,
|
||||
'value-names': {
|
||||
none: 'Hate Flowers',
|
||||
red: 'Red',
|
||||
@@ -1386,6 +1436,7 @@ export module Mock {
|
||||
name: 'Like Snow?',
|
||||
type: 'boolean',
|
||||
description: 'Do you like snow or not?',
|
||||
warning: null,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
@@ -1412,6 +1463,7 @@ export module Mock {
|
||||
type: 'number',
|
||||
integral: false,
|
||||
description: 'Your favorite number of all time',
|
||||
placeholder: null,
|
||||
warning:
|
||||
'Once you set this number, it can never be changed without severe consequences.',
|
||||
nullable: true,
|
||||
@@ -1424,9 +1476,12 @@ export module Mock {
|
||||
type: 'list',
|
||||
subtype: 'number',
|
||||
description: 'Numbers that you like but are not your top favorite.',
|
||||
warning: null,
|
||||
spec: {
|
||||
integral: false,
|
||||
range: '[-100,200)',
|
||||
units: null,
|
||||
placeholder: null,
|
||||
},
|
||||
range: '[0,10]',
|
||||
default: [2, 3],
|
||||
@@ -1441,6 +1496,7 @@ export module Mock {
|
||||
name: 'Laws',
|
||||
type: 'object',
|
||||
description: 'the law of the realm',
|
||||
warning: null,
|
||||
spec: {
|
||||
law1: {
|
||||
name: 'First Law',
|
||||
@@ -1448,7 +1504,12 @@ export module Mock {
|
||||
description: 'the first law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
law2: {
|
||||
name: 'Second Law',
|
||||
@@ -1456,7 +1517,12 @@ export module Mock {
|
||||
description: 'the second law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1465,10 +1531,12 @@ export module Mock {
|
||||
type: 'list',
|
||||
subtype: 'object',
|
||||
description: 'the people who make the rules',
|
||||
warning: null,
|
||||
range: '[0,2]',
|
||||
default: [],
|
||||
spec: {
|
||||
'unique-by': null,
|
||||
'display-as': null,
|
||||
spec: {
|
||||
rulemakername: {
|
||||
name: 'Rulemaker Name',
|
||||
@@ -1480,7 +1548,11 @@ export module Mock {
|
||||
len: 12,
|
||||
},
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
rulemakerip: {
|
||||
name: 'Rulemaker IP',
|
||||
@@ -1492,7 +1564,9 @@ export module Mock {
|
||||
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$',
|
||||
'pattern-description': 'may only contain numbers and periods',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1506,7 +1580,9 @@ export module Mock {
|
||||
pattern: '^[a-zA-Z]+$',
|
||||
'pattern-description': 'must contain only letters.',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
rpcpass: {
|
||||
name: 'RPC User Password',
|
||||
@@ -1518,7 +1594,11 @@ export module Mock {
|
||||
len: 20,
|
||||
},
|
||||
masked: true,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1570,7 +1650,9 @@ export module Mock {
|
||||
pattern: '.*',
|
||||
'pattern-description': 'anything',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
'private-domain': {
|
||||
name: 'Private Domain',
|
||||
@@ -1578,7 +1660,12 @@ export module Mock {
|
||||
description: 'the private address of the node',
|
||||
nullable: false,
|
||||
masked: true,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1589,9 +1676,12 @@ export module Mock {
|
||||
integral: true,
|
||||
description:
|
||||
'the default port for your Bitcoin node. default: 8333, testnet: 18333, regtest: 18444',
|
||||
warning: null,
|
||||
nullable: false,
|
||||
default: 8333,
|
||||
range: '(0, 9998]',
|
||||
units: null,
|
||||
placeholder: null,
|
||||
},
|
||||
'favorite-slogan': {
|
||||
name: 'Favorite Slogan',
|
||||
@@ -1600,7 +1690,12 @@ export module Mock {
|
||||
'You most favorite slogan in the whole world, used for paying you.',
|
||||
nullable: true,
|
||||
masked: true,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
rpcallowip: {
|
||||
name: 'RPC Allowed IPs',
|
||||
@@ -1614,7 +1709,7 @@ export module Mock {
|
||||
default: ['192.168.1.1'],
|
||||
spec: {
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern:
|
||||
'((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}:){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-description': 'must be a valid ipv4, ipv6, or domain name',
|
||||
@@ -1625,23 +1720,28 @@ export module Mock {
|
||||
type: 'list',
|
||||
subtype: 'string',
|
||||
description: 'api keys that are authorized to access your Bitcoin node.',
|
||||
warning: null,
|
||||
range: '[0,*)',
|
||||
default: [],
|
||||
spec: {
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
},
|
||||
},
|
||||
'more-advanced': {
|
||||
name: 'More Advanced',
|
||||
type: 'object',
|
||||
description: 'Advanced settings',
|
||||
warning: null,
|
||||
spec: {
|
||||
notifications: {
|
||||
name: 'Notification Preferences',
|
||||
type: 'list',
|
||||
subtype: 'enum',
|
||||
description: 'how you want to be notified',
|
||||
warning: null,
|
||||
range: '[1,3]',
|
||||
default: ['email'],
|
||||
spec: {
|
||||
@@ -1666,6 +1766,7 @@ export module Mock {
|
||||
name: 'Laws',
|
||||
type: 'object',
|
||||
description: 'the law of the realm',
|
||||
warning: null,
|
||||
spec: {
|
||||
law1: {
|
||||
name: 'First Law',
|
||||
@@ -1673,7 +1774,12 @@ export module Mock {
|
||||
description: 'the first law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
law2: {
|
||||
name: 'Second Law',
|
||||
@@ -1681,7 +1787,12 @@ export module Mock {
|
||||
description: 'the second law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
law4: {
|
||||
name: 'Fourth Law',
|
||||
@@ -1689,17 +1800,24 @@ export module Mock {
|
||||
description: 'the fourth law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
law3: {
|
||||
name: 'Third Law',
|
||||
type: 'list',
|
||||
subtype: 'object',
|
||||
description: 'the third law',
|
||||
warning: null,
|
||||
range: '[0,2]',
|
||||
default: [],
|
||||
spec: {
|
||||
'unique-by': null,
|
||||
'display-as': null,
|
||||
spec: {
|
||||
lawname: {
|
||||
name: 'Law Name',
|
||||
@@ -1711,7 +1829,11 @@ export module Mock {
|
||||
len: 12,
|
||||
},
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
lawagency: {
|
||||
name: 'Law agency',
|
||||
@@ -1724,7 +1846,9 @@ export module Mock {
|
||||
'pattern-description':
|
||||
'may only contain numbers and periods',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1735,7 +1859,12 @@ export module Mock {
|
||||
description: 'the fifth law',
|
||||
nullable: true,
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1744,10 +1873,12 @@ export module Mock {
|
||||
type: 'list',
|
||||
subtype: 'object',
|
||||
description: 'the people who make the rules',
|
||||
warning: null,
|
||||
range: '[0,2]',
|
||||
default: [],
|
||||
spec: {
|
||||
'unique-by': null,
|
||||
'display-as': null,
|
||||
spec: {
|
||||
rulemakername: {
|
||||
name: 'Rulemaker Name',
|
||||
@@ -1759,7 +1890,11 @@ export module Mock {
|
||||
len: 12,
|
||||
},
|
||||
masked: false,
|
||||
copyable: false,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
rulemakerip: {
|
||||
name: 'Rulemaker IP',
|
||||
@@ -1772,7 +1907,9 @@ export module Mock {
|
||||
'pattern-description':
|
||||
'may only contain numbers and periods',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1786,7 +1923,9 @@ export module Mock {
|
||||
pattern: '^[a-zA-Z]+$',
|
||||
'pattern-description': 'must contain only letters.',
|
||||
masked: false,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
rpcpass: {
|
||||
name: 'RPC User Password',
|
||||
@@ -1798,7 +1937,11 @@ export module Mock {
|
||||
len: 20,
|
||||
},
|
||||
masked: true,
|
||||
copyable: true,
|
||||
placeholder: null,
|
||||
pattern: null,
|
||||
'pattern-description': null,
|
||||
textarea: false,
|
||||
warning: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Dump, Revision } from 'patch-db-client'
|
||||
import { MarketplacePkg, StoreInfo } from '@start9labs/marketplace'
|
||||
import { PackagePropertiesVersioned } from 'src/app/util/properties.util'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import {
|
||||
DataModel,
|
||||
DependencyError,
|
||||
@@ -253,6 +253,7 @@ export module RR {
|
||||
export type SideloadPackageReq = {
|
||||
manifest: Manifest
|
||||
icon: string // base64
|
||||
size: number // bytes
|
||||
}
|
||||
export type SideloadPacakgeRes = string //guid
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
ValueSpecObject,
|
||||
ValueSpecString,
|
||||
ValueSpecUnion,
|
||||
} from 'src/app/pkg-config/config-types'
|
||||
import { getDefaultString, Range } from '../pkg-config/config-utilities'
|
||||
} from 'start-sdk/types/config-types'
|
||||
import { getDefaultString, Range } from '../util/config-utilities'
|
||||
const Mustache = require('mustache')
|
||||
|
||||
@Injectable({
|
||||
@@ -360,7 +360,7 @@ function listObjEquals(
|
||||
val1: any,
|
||||
val2: any,
|
||||
): boolean {
|
||||
if (uniqueBy === null) {
|
||||
if (!uniqueBy) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
return itemEquals(spec.spec[uniqueBy], val1[uniqueBy], val2[uniqueBy])
|
||||
@@ -388,7 +388,7 @@ function objEquals(
|
||||
val1: any,
|
||||
val2: any,
|
||||
): boolean {
|
||||
if (uniqueBy === null) {
|
||||
if (!uniqueBy) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
// TODO: fix types
|
||||
@@ -419,7 +419,7 @@ function unionEquals(
|
||||
): boolean {
|
||||
const tagId = spec.tag.id
|
||||
const variant = spec.variants[val1[tagId]]
|
||||
if (uniqueBy === null) {
|
||||
if (!uniqueBy) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
if (uniqueBy === tagId) {
|
||||
@@ -474,7 +474,7 @@ function uniqueByMessage(
|
||||
): string {
|
||||
let joinFunc
|
||||
const subSpecs: string[] = []
|
||||
if (uniqueBy === null) {
|
||||
if (!uniqueBy) {
|
||||
return ''
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
return configSpec[uniqueBy]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { ConfigSpec } from 'start-sdk/types/config-types'
|
||||
import { Url } from '@start9labs/shared'
|
||||
import { MarketplaceManifest } from '@start9labs/marketplace'
|
||||
import { BasicInfo } from 'src/app/pages/developer-routes/developer-menu/form-info'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { isEmptyObject } from '@start9labs/shared'
|
||||
import {
|
||||
InstalledPackageDataEntry,
|
||||
MainStatusStarting,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ValueSpec, DefaultString } from './config-types'
|
||||
import { ValueSpec, DefaultString } from 'start-sdk/types/config-types'
|
||||
|
||||
export class Range {
|
||||
min?: number
|
||||
@@ -1,4 +1,8 @@
|
||||
import { PackageDataEntry } from '../services/patch-db/data-model'
|
||||
import {
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from '../services/patch-db/data-model'
|
||||
import {
|
||||
DependencyStatus,
|
||||
HealthStatus,
|
||||
@@ -35,7 +39,7 @@ export function getPackageInfo(entry: PackageDataEntry): PkgInfo {
|
||||
export interface PkgInfo {
|
||||
entry: PackageDataEntry
|
||||
primaryRendering: StatusRendering
|
||||
primaryStatus: PrimaryStatus
|
||||
primaryStatus: PrimaryStatus | PackageState | PackageMainStatus
|
||||
installProgress: ProgressData | null
|
||||
error: boolean
|
||||
warning: boolean
|
||||
|
||||
4
libs/Cargo.lock
generated
4
libs/Cargo.lock
generated
@@ -3008,9 +3008,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.91"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Deno from "/deno_global.js";
|
||||
import * as mainModule from "/embassy.js";
|
||||
|
||||
function requireParam(param) {
|
||||
throw new Error(`Missing required parameter ${param}`);
|
||||
}
|
||||
@@ -90,7 +89,10 @@ const bindLocal = async (
|
||||
externalPort = requireParam("externalPort"),
|
||||
} = requireParam("options"),
|
||||
) => {
|
||||
return Deno.core.opAsync("bind_local", internalPort, { name, externalPort });
|
||||
return Deno.core.opAsync("bind_local", internalPort, {
|
||||
id: name,
|
||||
externalPort,
|
||||
});
|
||||
};
|
||||
const bindTor = async (
|
||||
{
|
||||
@@ -99,7 +101,10 @@ const bindTor = async (
|
||||
externalPort = requireParam("externalPort"),
|
||||
} = requireParam("options"),
|
||||
) => {
|
||||
return Deno.core.opAsync("bind_onion", internalPort, { name, externalPort });
|
||||
return Deno.core.opAsync("bind_onion", internalPort, {
|
||||
id: name,
|
||||
externalPort,
|
||||
});
|
||||
};
|
||||
|
||||
const signalGroup = async (
|
||||
@@ -180,7 +185,8 @@ const createDir = (
|
||||
) => Deno.core.opAsync("create_dir", volumeId, path);
|
||||
|
||||
const readDir = (
|
||||
{ volumeId = requireParam("volumeId"), path = requireParam("path") } = requireParam("options"),
|
||||
{ volumeId = requireParam("volumeId"), path = requireParam("path") } =
|
||||
requireParam("options"),
|
||||
) => Deno.core.opAsync("read_dir", volumeId, path);
|
||||
const removeDir = (
|
||||
{ volumeId = requireParam("volumeId"), path = requireParam("path") } =
|
||||
@@ -289,12 +295,15 @@ const effects = {
|
||||
removeDir,
|
||||
removeFile,
|
||||
rename,
|
||||
restart,
|
||||
runCommand,
|
||||
runDaemon,
|
||||
runRsync,
|
||||
chmod,
|
||||
signalGroup,
|
||||
sleep,
|
||||
start,
|
||||
stop,
|
||||
trace,
|
||||
warn,
|
||||
writeFile,
|
||||
|
||||
@@ -19,6 +19,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tracing::instrument;
|
||||
|
||||
pub trait PathForVolumeId: Send + Sync {
|
||||
fn path_for(
|
||||
@@ -330,6 +331,7 @@ impl JsExecutionEnvironment {
|
||||
]
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
async fn execute(
|
||||
self,
|
||||
procedure_name: ProcedureName,
|
||||
@@ -371,7 +373,6 @@ impl JsExecutionEnvironment {
|
||||
Ok(())
|
||||
})
|
||||
.build();
|
||||
|
||||
let loader = std::rc::Rc::new(self.module_loader.clone());
|
||||
let runtime_options = RuntimeOptions {
|
||||
module_loader: Some(loader),
|
||||
@@ -395,7 +396,6 @@ impl JsExecutionEnvironment {
|
||||
evaluated.await??;
|
||||
Ok::<_, AnyError>(())
|
||||
};
|
||||
|
||||
let answer = tokio::select! {
|
||||
Some(x) = receive_answer.recv() => x,
|
||||
_ = future => {
|
||||
|
||||
@@ -24,7 +24,7 @@ rand = "0.8"
|
||||
regex = "1.7.1"
|
||||
rpc-toolkit = "0.2.1"
|
||||
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.82"
|
||||
serde_json = "1.0"
|
||||
sqlx = { version = "0.6.0", features = [
|
||||
"chrono",
|
||||
"offline",
|
||||
|
||||
24
system-images/compat/Cargo.lock
generated
24
system-images/compat/Cargo.lock
generated
@@ -262,6 +262,15 @@ dependencies = [
|
||||
"itertools 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bimap"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@@ -1181,6 +1190,7 @@ dependencies = [
|
||||
"base64 0.13.1",
|
||||
"base64ct",
|
||||
"basic-cookies",
|
||||
"bimap",
|
||||
"bollard",
|
||||
"bytes",
|
||||
"chrono",
|
||||
@@ -1207,6 +1217,7 @@ dependencies = [
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-ws-listener",
|
||||
"id-pool",
|
||||
"imbl 2.0.0",
|
||||
"indexmap",
|
||||
"ipnet",
|
||||
@@ -1974,6 +1985,15 @@ dependencies = [
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-pool"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d0df4d8a768821ee4aa2e0353f67125c4586f0e13adbf95b8ebbf8d8fdb344"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
@@ -3802,9 +3822,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.91"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa 1.0.5",
|
||||
|
||||
Reference in New Issue
Block a user