mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Feature/registry improvements (#2772)
* add build cli script for cross-building cli * sdk alpha.13 * registry improvements
This commit is contained in:
2
Makefile
2
Makefile
@@ -58,7 +58,7 @@ touch:
|
||||
metadata: $(VERSION_FILE) $(PLATFORM_FILE) $(ENVIRONMENT_FILE) $(GIT_HASH_FILE)
|
||||
|
||||
sudo:
|
||||
sudo -v
|
||||
sudo true
|
||||
|
||||
clean:
|
||||
rm -f system-images/**/*.tar
|
||||
|
||||
88
core/Cargo.lock
generated
88
core/Cargo.lock
generated
@@ -128,9 +128,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
@@ -162,9 +162,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.91"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
|
||||
checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
@@ -237,7 +237,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -248,7 +248,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -538,7 +538,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
"which",
|
||||
]
|
||||
|
||||
@@ -847,7 +847,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1255,7 +1255,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1279,7 +1279,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.11.1",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1290,7 +1290,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1344,7 +1344,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1367,7 +1367,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1589,7 +1589,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1868,7 +1868,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2849,9 +2849,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a00419de735aac21d53b0de5ce2c03bd3627277cf471300f27ebc89f7d828047"
|
||||
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -3302,7 +3302,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3368,7 +3368,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3575,7 +3575,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3631,7 +3631,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3707,7 +3707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3805,7 +3805,7 @@ checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3828,7 +3828,7 @@ dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4169,7 +4169,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rpc-toolkit"
|
||||
version = "0.2.3"
|
||||
source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=refactor%2Fno-dyn-ctx#39a872a1294c7d864faca63f072092ce300ffbe5"
|
||||
source = "git+https://github.com/Start9Labs/rpc-toolkit.git?branch=refactor%2Fno-dyn-ctx#021379f21c4d11c5a62c07460f4531ce9b555155"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
@@ -4496,7 +4496,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4570,7 +4570,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5003,7 +5003,7 @@ dependencies = [
|
||||
"quote",
|
||||
"regex-syntax 0.6.29",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
@@ -5245,9 +5245,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.85"
|
||||
version = "2.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
|
||||
checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5363,22 +5363,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
|
||||
checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
|
||||
checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5494,7 +5494,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5768,7 +5768,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5920,7 +5920,7 @@ dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@@ -5990,7 +5990,7 @@ checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6215,7 +6215,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -6249,7 +6249,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -6633,7 +6633,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6653,7 +6653,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.85",
|
||||
"syn 2.0.86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
50
core/build-cli.sh
Executable file
50
core/build-cli.sh
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
set -ea
|
||||
shopt -s expand_aliases
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
ARCH=$(uname -m)
|
||||
fi
|
||||
if [ "$ARCH" = "arm64" ]; then
|
||||
ARCH="aarch64"
|
||||
fi
|
||||
|
||||
if [ -z "$KERNEL_NAME" ]; then
|
||||
KERNEL_NAME=$(uname -s)
|
||||
fi
|
||||
|
||||
if [ -z "$TARGET" ]; then
|
||||
if [ "$KERNEL_NAME" = "Linux" ]; then
|
||||
TARGET="$ARCH-unknown-linux-musl"
|
||||
elif [ "$KERNEL_NAME" = "Darwin" ]; then
|
||||
TARGET="$ARCH-apple-darwin"
|
||||
else
|
||||
>&2 echo "unknown kernel $KERNEL_NAME"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
USE_TTY=
|
||||
if tty -s; then
|
||||
USE_TTY="-it"
|
||||
fi
|
||||
|
||||
cd ..
|
||||
FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')"
|
||||
RUSTFLAGS=""
|
||||
|
||||
if [[ "${ENVIRONMENT}" =~ (^|-)unstable($|-) ]]; then
|
||||
RUSTFLAGS="--cfg tokio_unstable"
|
||||
fi
|
||||
|
||||
alias 'rust-zig-builder'='docker run $USE_TTY --rm -e "RUSTFLAGS=$RUSTFLAGS" -v "$HOME/.cargo/registry":/root/.cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$(pwd)":/home/rust/src -w /home/rust/src -P messense/cargo-zigbuild'
|
||||
|
||||
echo "FEATURES=\"$FEATURES\""
|
||||
echo "RUSTFLAGS=\"$RUSTFLAGS\""
|
||||
rust-zig-builder sh -c "cd core && cargo zigbuild --release --no-default-features --features cli,daemon,$FEATURES --locked --bin start-cli --target=$TARGET"
|
||||
if [ "$(ls -nd core/target/$TARGET/release/start-cli | awk '{ print $3 }')" != "$UID" ]; then
|
||||
rust-zig-builder sh -c "cd core && chown -R $UID:$UID target && chown -R $UID:$UID /root/.cargo"
|
||||
fi
|
||||
13
core/startos/registry.service
Normal file
13
core/startos/registry.service
Normal file
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=StartOS Registry
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=RUST_LOG=startos=debug,patch_db=warn
|
||||
ExecStart=/usr/local/bin/registry
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
ManagedOOMPreference=avoid
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -28,6 +28,16 @@ fn select_executable(name: &str) -> Option<fn(VecDeque<OsString>)> {
|
||||
"embassy-sdk" => Some(|_| deprecated::renamed("embassy-sdk", "start-sdk")),
|
||||
"embassyd" => Some(|_| deprecated::renamed("embassyd", "startd")),
|
||||
"embassy-init" => Some(|_| deprecated::removed("embassy-init")),
|
||||
"contents" => Some(|_| {
|
||||
#[cfg(feature = "cli")]
|
||||
println!("start-cli");
|
||||
#[cfg(feature = "container-runtime")]
|
||||
println!("start-cli (container)");
|
||||
#[cfg(feature = "daemon")]
|
||||
println!("startd");
|
||||
#[cfg(feature = "registry")]
|
||||
println!("registry");
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,7 @@ pub fn main_api<C: Context>() -> ParentHandler<C> {
|
||||
let api = ParentHandler::new()
|
||||
.subcommand(
|
||||
"git-info",
|
||||
from_fn(|_: RpcContext| version::git_info())
|
||||
.with_about("Display the githash of StartOS CLI"),
|
||||
from_fn(|_: C| version::git_info()).with_about("Display the githash of StartOS CLI"),
|
||||
)
|
||||
.subcommand(
|
||||
"echo",
|
||||
|
||||
@@ -360,11 +360,7 @@ pub fn logs<
|
||||
source: impl for<'a> LogSourceFn<'a, C, Extra>,
|
||||
) -> ParentHandler<C, LogsParams<Extra>> {
|
||||
ParentHandler::new()
|
||||
.root_handler(
|
||||
logs_nofollow::<C, Extra>(source.clone())
|
||||
.with_inherited(|params, _| params)
|
||||
.no_cli(),
|
||||
)
|
||||
.root_handler(logs_nofollow::<C, Extra>(source.clone()).no_cli())
|
||||
.subcommand(
|
||||
"follow",
|
||||
logs_follow::<C, Extra>(source)
|
||||
@@ -436,7 +432,7 @@ where
|
||||
|
||||
fn logs_nofollow<C, Extra>(
|
||||
f: impl for<'a> LogSourceFn<'a, C, Extra>,
|
||||
) -> impl HandlerFor<C, Params = Empty, InheritedParams = LogsParams<Extra>, Ok = LogResponse, Err = Error>
|
||||
) -> impl HandlerFor<C, Params = LogsParams<Extra>, InheritedParams = Empty, Ok = LogResponse, Err = Error>
|
||||
where
|
||||
C: Context,
|
||||
Extra: FromArgMatches + Args + Send + Sync + 'static,
|
||||
@@ -444,7 +440,7 @@ where
|
||||
from_fn_async(
|
||||
move |HandlerArgs {
|
||||
context,
|
||||
inherited_params:
|
||||
params:
|
||||
LogsParams {
|
||||
extra,
|
||||
limit,
|
||||
@@ -453,7 +449,7 @@ where
|
||||
before,
|
||||
},
|
||||
..
|
||||
}: HandlerArgs<C, Empty, LogsParams<Extra>>| {
|
||||
}: HandlerArgs<C, LogsParams<Extra>>| {
|
||||
let f = f.clone();
|
||||
async move {
|
||||
fetch_logs(
|
||||
|
||||
@@ -60,6 +60,13 @@ fn signers_api<C: Context>() -> ParentHandler<C> {
|
||||
"add",
|
||||
from_fn_async(cli_add_signer).with_about("Add signer"),
|
||||
)
|
||||
.subcommand(
|
||||
"edit",
|
||||
from_fn_async(edit_signer)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
impl Model<BTreeMap<Guid, SignerInfo>> {
|
||||
@@ -143,6 +150,64 @@ pub async fn add_signer(ctx: RegistryContext, signer: SignerInfo) -> Result<Guid
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[ts(export)]
|
||||
pub struct EditSignerParams {
|
||||
pub id: Guid,
|
||||
#[arg(short = 'n', long)]
|
||||
pub set_name: Option<String>,
|
||||
#[arg(short = 'c', long)]
|
||||
pub add_contact: Vec<ContactInfo>,
|
||||
#[arg(short = 'k', long)]
|
||||
pub add_key: Vec<AnyVerifyingKey>,
|
||||
#[arg(short = 'C', long)]
|
||||
pub remove_contact: Vec<ContactInfo>,
|
||||
#[arg(short = 'K', long)]
|
||||
pub remove_key: Vec<AnyVerifyingKey>,
|
||||
}
|
||||
|
||||
pub async fn edit_signer(
|
||||
ctx: RegistryContext,
|
||||
EditSignerParams {
|
||||
id,
|
||||
set_name,
|
||||
add_contact,
|
||||
add_key,
|
||||
remove_contact,
|
||||
remove_key,
|
||||
}: EditSignerParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_index_mut()
|
||||
.as_signers_mut()
|
||||
.as_idx_mut(&id)
|
||||
.or_not_found(&id)?
|
||||
.mutate(|s| {
|
||||
if let Some(name) = set_name {
|
||||
s.name = name;
|
||||
}
|
||||
s.contact.extend(add_contact);
|
||||
for rm in remove_contact {
|
||||
let Some((idx, _)) = s.contact.iter().enumerate().find(|(_, c)| *c == &rm)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
s.contact.remove(idx);
|
||||
}
|
||||
|
||||
s.keys.extend(add_key);
|
||||
for rm in remove_key {
|
||||
s.keys.remove(&rm);
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
|
||||
126
core/startos/src/registry/info.rs
Normal file
126
core/startos/src/registry/info.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
use imbl_value::InternedString;
|
||||
use itertools::Itertools;
|
||||
use models::DataUrl;
|
||||
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerArgs, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::CliContext;
|
||||
use crate::prelude::*;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::package::index::Category;
|
||||
use crate::util::serde::{HandlerExtSerde, WithIoFormat};
|
||||
|
||||
pub fn info_api<C: Context>() -> ParentHandler<C, WithIoFormat<Empty>> {
|
||||
ParentHandler::<C, WithIoFormat<Empty>>::new()
|
||||
.root_handler(
|
||||
from_fn_async(get_info)
|
||||
.with_display_serializable()
|
||||
.with_about("Display registry name, icon, and package categories")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"set-name",
|
||||
from_fn_async(set_name)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Set the name for the registry")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"set-icon",
|
||||
from_fn_async(set_icon)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_cli(),
|
||||
)
|
||||
.subcommand(
|
||||
"set-icon",
|
||||
from_fn_async(cli_set_icon)
|
||||
.no_display()
|
||||
.with_about("Set the icon for the registry"),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct RegistryInfo {
|
||||
pub name: Option<String>,
|
||||
pub icon: Option<DataUrl<'static>>,
|
||||
#[ts(as = "BTreeMap::<String, Category>")]
|
||||
pub categories: BTreeMap<InternedString, Category>,
|
||||
}
|
||||
|
||||
pub async fn get_info(ctx: RegistryContext) -> Result<RegistryInfo, Error> {
|
||||
let peek = ctx.db.peek().await.into_index();
|
||||
Ok(RegistryInfo {
|
||||
name: peek.as_name().de()?,
|
||||
icon: peek.as_icon().de()?,
|
||||
categories: peek.as_package().as_categories().de()?,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct SetNameParams {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub async fn set_name(
|
||||
ctx: RegistryContext,
|
||||
SetNameParams { name }: SetNameParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| db.as_index_mut().as_name_mut().ser(&Some(name)))
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct SetIconParams {
|
||||
pub icon: DataUrl<'static>,
|
||||
}
|
||||
|
||||
pub async fn set_icon(
|
||||
ctx: RegistryContext,
|
||||
SetIconParams { icon }: SetIconParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| db.as_index_mut().as_icon_mut().ser(&Some(icon)))
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct CliSetIconParams {
|
||||
pub icon: PathBuf,
|
||||
}
|
||||
|
||||
pub async fn cli_set_icon(
|
||||
HandlerArgs {
|
||||
context: ctx,
|
||||
parent_method,
|
||||
method,
|
||||
params: CliSetIconParams { icon },
|
||||
..
|
||||
}: HandlerArgs<CliContext, CliSetIconParams>,
|
||||
) -> Result<(), Error> {
|
||||
let data_url = DataUrl::from_path(icon).await?;
|
||||
ctx.call_remote::<RegistryContext>(
|
||||
&parent_method.into_iter().chain(method).join("."),
|
||||
imbl_value::json!({
|
||||
"icon": data_url,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -28,6 +28,7 @@ pub mod auth;
|
||||
pub mod context;
|
||||
pub mod db;
|
||||
pub mod device_info;
|
||||
pub mod info;
|
||||
pub mod os;
|
||||
pub mod package;
|
||||
pub mod signer;
|
||||
@@ -57,25 +58,6 @@ pub async fn get_full_index(ctx: RegistryContext) -> Result<FullIndex, Error> {
|
||||
ctx.db.peek().await.into_index().de()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct RegistryInfo {
|
||||
pub name: Option<String>,
|
||||
pub icon: Option<DataUrl<'static>>,
|
||||
#[ts(as = "BTreeMap::<String, Category>")]
|
||||
pub categories: BTreeMap<InternedString, Category>,
|
||||
}
|
||||
|
||||
pub async fn get_info(ctx: RegistryContext) -> Result<RegistryInfo, Error> {
|
||||
let peek = ctx.db.peek().await.into_index();
|
||||
Ok(RegistryInfo {
|
||||
name: peek.as_name().de()?,
|
||||
icon: peek.as_icon().de()?,
|
||||
categories: peek.as_package().as_categories().de()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn registry_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
@@ -85,13 +67,8 @@ pub fn registry_api<C: Context>() -> ParentHandler<C> {
|
||||
.with_about("List info including registry name and packages")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"info",
|
||||
from_fn_async(get_info)
|
||||
.with_display_serializable()
|
||||
.with_about("Display registry name, icon, and package categories")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand("info", info::info_api::<C>())
|
||||
// set info and categories
|
||||
.subcommand(
|
||||
"os",
|
||||
os::os_api::<C>().with_about("Commands related to OS assets and versions"),
|
||||
|
||||
@@ -40,7 +40,12 @@ pub fn get_api<C: Context>() -> ParentHandler<C> {
|
||||
.with_about("Download img"),
|
||||
)
|
||||
.subcommand("squashfs", from_fn_async(get_squashfs).no_cli())
|
||||
.subcommand("squashfs", from_fn_async(cli_get_os_asset).no_display().with_about("Download squashfs"))
|
||||
.subcommand(
|
||||
"squashfs",
|
||||
from_fn_async(cli_get_os_asset)
|
||||
.no_display()
|
||||
.with_about("Download squashfs"),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
@@ -104,7 +109,11 @@ pub async fn get_squashfs(
|
||||
pub struct CliGetOsAssetParams {
|
||||
pub version: Version,
|
||||
pub platform: InternedString,
|
||||
#[arg(long = "download", short = 'd')]
|
||||
#[arg(
|
||||
long = "download",
|
||||
short = 'd',
|
||||
help = "The path of the directory to download to"
|
||||
)]
|
||||
pub download: Option<PathBuf>,
|
||||
#[arg(
|
||||
long = "reverify",
|
||||
|
||||
147
core/startos/src/registry/package/category.rs
Normal file
147
core/startos/src/registry/package/category.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clap::Parser;
|
||||
use imbl_value::InternedString;
|
||||
use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::CliContext;
|
||||
use crate::prelude::*;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::package::index::Category;
|
||||
use crate::s9pk::manifest::Description;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde, WithIoFormat};
|
||||
|
||||
pub fn category_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"add",
|
||||
from_fn_async(add_category)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Add a category to the registry")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"remove",
|
||||
from_fn_async(remove_category)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Remove a category from the registry")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"list",
|
||||
from_fn_async(list_categories)
|
||||
.with_display_serializable()
|
||||
.with_custom_display_fn(|params, categories| {
|
||||
Ok(display_categories(params.params, categories))
|
||||
})
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct AddCategoryParams {
|
||||
#[ts(type = "string")]
|
||||
pub id: InternedString,
|
||||
pub name: String,
|
||||
#[arg(short, long, help = "Short description for the category")]
|
||||
pub short: String,
|
||||
#[arg(short, long, help = "Long description for the category")]
|
||||
pub long: String,
|
||||
}
|
||||
|
||||
pub async fn add_category(
|
||||
ctx: RegistryContext,
|
||||
AddCategoryParams {
|
||||
id,
|
||||
name,
|
||||
short,
|
||||
long,
|
||||
}: AddCategoryParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_categories_mut()
|
||||
.insert(
|
||||
&id,
|
||||
&Category {
|
||||
name,
|
||||
description: Description { short, long },
|
||||
},
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct RemoveCategoryParams {
|
||||
#[ts(type = "string")]
|
||||
pub id: InternedString,
|
||||
}
|
||||
|
||||
pub async fn remove_category(
|
||||
ctx: RegistryContext,
|
||||
RemoveCategoryParams { id }: RemoveCategoryParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_categories_mut()
|
||||
.remove(&id)
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_categories(
|
||||
ctx: RegistryContext,
|
||||
) -> Result<BTreeMap<InternedString, Category>, Error> {
|
||||
ctx.db
|
||||
.peek()
|
||||
.await
|
||||
.into_index()
|
||||
.into_package()
|
||||
.into_categories()
|
||||
.de()
|
||||
}
|
||||
|
||||
pub fn display_categories<T>(
|
||||
params: WithIoFormat<T>,
|
||||
categories: BTreeMap<InternedString, Category>,
|
||||
) {
|
||||
use prettytable::*;
|
||||
|
||||
if let Some(format) = params.format {
|
||||
return display_serializable(format, categories);
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![bc =>
|
||||
"ID",
|
||||
"NAME",
|
||||
"SHORT DESCRIPTION",
|
||||
"LONG DESCRIPTION",
|
||||
]);
|
||||
for (id, info) in categories {
|
||||
table.add_row(row![
|
||||
&*id,
|
||||
&info.name,
|
||||
&info.description.short,
|
||||
&info.description.long,
|
||||
]);
|
||||
}
|
||||
table.print_tty(false).unwrap();
|
||||
}
|
||||
@@ -5,8 +5,10 @@ use crate::prelude::*;
|
||||
use crate::util::serde::HandlerExtSerde;
|
||||
|
||||
pub mod add;
|
||||
pub mod category;
|
||||
pub mod get;
|
||||
pub mod index;
|
||||
pub mod signer;
|
||||
|
||||
pub fn package_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
@@ -29,6 +31,10 @@ pub fn package_api<C: Context>() -> ParentHandler<C> {
|
||||
.no_display()
|
||||
.with_about("Add package to registry index"),
|
||||
)
|
||||
.subcommand(
|
||||
"signer",
|
||||
signer::signer_api::<C>().with_about("Add, remove, and list package signers"),
|
||||
)
|
||||
.subcommand(
|
||||
"get",
|
||||
from_fn_async(get::get_package)
|
||||
@@ -40,4 +46,9 @@ pub fn package_api<C: Context>() -> ParentHandler<C> {
|
||||
.with_about("List installation candidate package(s)")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"category",
|
||||
category::category_api::<C>()
|
||||
.with_about("Update the categories for packages on the registry"),
|
||||
)
|
||||
}
|
||||
|
||||
133
core/startos/src/registry/package/signer.rs
Normal file
133
core/startos/src/registry/package/signer.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clap::Parser;
|
||||
use models::PackageId;
|
||||
use rpc_toolkit::{from_fn_async, Context, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::context::CliContext;
|
||||
use crate::prelude::*;
|
||||
use crate::registry::admin::display_signers;
|
||||
use crate::registry::context::RegistryContext;
|
||||
use crate::registry::signer::SignerInfo;
|
||||
use crate::rpc_continuations::Guid;
|
||||
use crate::util::serde::HandlerExtSerde;
|
||||
|
||||
pub fn signer_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"add",
|
||||
from_fn_async(add_package_signer)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Add package signer")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"remove",
|
||||
from_fn_async(remove_package_signer)
|
||||
.with_metadata("admin", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Remove package signer")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"list",
|
||||
from_fn_async(list_package_signers)
|
||||
.with_display_serializable()
|
||||
.with_custom_display_fn(|handle, result| Ok(display_signers(handle.params, result)))
|
||||
.with_about("List package signers and related signer info")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct PackageSignerParams {
|
||||
pub id: PackageId,
|
||||
pub signer: Guid,
|
||||
}
|
||||
|
||||
pub async fn add_package_signer(
|
||||
ctx: RegistryContext,
|
||||
PackageSignerParams { id, signer }: PackageSignerParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
ensure_code!(
|
||||
db.as_index().as_signers().contains_key(&signer)?,
|
||||
ErrorKind::InvalidRequest,
|
||||
"unknown signer {signer}"
|
||||
);
|
||||
|
||||
db.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.as_idx_mut(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_authorized_mut()
|
||||
.mutate(|s| Ok(s.insert(signer)))?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn remove_package_signer(
|
||||
ctx: RegistryContext,
|
||||
PackageSignerParams { id, signer }: PackageSignerParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
if !db
|
||||
.as_index_mut()
|
||||
.as_package_mut()
|
||||
.as_packages_mut()
|
||||
.as_idx_mut(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_authorized_mut()
|
||||
.mutate(|s| Ok(s.remove(&signer)))?
|
||||
{
|
||||
return Err(Error::new(
|
||||
eyre!("signer {signer} is not authorized to sign for {id}"),
|
||||
ErrorKind::NotFound,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct ListPackageSignersParams {
|
||||
pub id: PackageId,
|
||||
}
|
||||
|
||||
pub async fn list_package_signers(
|
||||
ctx: RegistryContext,
|
||||
ListPackageSignersParams { id }: ListPackageSignersParams,
|
||||
) -> Result<BTreeMap<Guid, SignerInfo>, Error> {
|
||||
let db = ctx.db.peek().await;
|
||||
db.as_index()
|
||||
.as_package()
|
||||
.as_packages()
|
||||
.as_idx(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_authorized()
|
||||
.de()?
|
||||
.into_iter()
|
||||
.filter_map(|guid| {
|
||||
db.as_index()
|
||||
.as_signers()
|
||||
.as_idx(&guid)
|
||||
.map(|s| s.de().map(|s| (guid, s)))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -25,7 +25,7 @@ pub struct SignerInfo {
|
||||
pub keys: HashSet<AnyVerifyingKey>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
// TODO: better types
|
||||
|
||||
@@ -3,7 +3,7 @@ Description=StartOS Daemon
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=RUST_LOG=startos=debug,js_engine=debug,patch_db=warn
|
||||
Environment=RUST_LOG=startos=debug,patch_db=warn
|
||||
ExecStart=/usr/bin/startd
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "../../../base/lib/types/ManifestTypes"
|
||||
import { SDKVersion } from "../StartSdk"
|
||||
import { VersionGraph } from "../version/VersionGraph"
|
||||
import { execSync } from "child_process"
|
||||
|
||||
/**
|
||||
* @description Use this function to define critical information about your package
|
||||
@@ -26,6 +27,16 @@ export function setupManifest<
|
||||
return manifest
|
||||
}
|
||||
|
||||
function gitHash(): string {
|
||||
const hash = execSync("git rev-parse HEAD").toString().trim()
|
||||
try {
|
||||
execSync("git diff-index --quiet HEAD --")
|
||||
return hash
|
||||
} catch (e) {
|
||||
return hash + "-modified"
|
||||
}
|
||||
}
|
||||
|
||||
export function buildManifest<
|
||||
Id extends string,
|
||||
Version extends string,
|
||||
@@ -56,7 +67,7 @@ export function buildManifest<
|
||||
)
|
||||
return {
|
||||
...manifest,
|
||||
gitHash: null,
|
||||
gitHash: gitHash(),
|
||||
osVersion: SDKVersion,
|
||||
version: versions.current.options.version,
|
||||
releaseNotes: versions.current.options.releaseNotes,
|
||||
|
||||
4
sdk/package/package-lock.json
generated
4
sdk/package/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-alpha9",
|
||||
"version": "0.3.6-alpha.13",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-alpha9",
|
||||
"version": "0.3.6-alpha.13",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.3.6-alpha.12",
|
||||
"version": "0.3.6-alpha.13",
|
||||
"description": "Software development kit to facilitate packaging services for StartOS",
|
||||
"main": "./package/lib/index.js",
|
||||
"types": "./package/lib/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user